c++ class template specialization, without having to reimplement everything
Yes, it's possible in C++03 with CRTP (Curiously recurring template pattern):
#include <numeric>
#include <vector>
template<typename Derived, typename T>
struct Base
{
};
template<typename Derived>
struct Base<Derived, int>
{
int Sum() const
{
return std::accumulate(static_cast<Derived const*>(this)->myVector.begin(), static_cast<Derived const*>(this)->myVector.end(), int());
}
};
template<typename T>
class A : public Base<A<T>, T>
{
friend class Base<A<T>, T>;
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
};
int main()
{
A<int> Foo;
Foo.Sum();
}
The simplest and cleanest solution is to use a static_assert()
in the body of a method, rejecting other types than the selected one (in the below example only integers are accepted):
#include <type_traits>
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
static_assert(std::is_same<T, int>::value, "Works only with ints!");
}
protected:
std::vector<T> myVector;
};
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
//f.onlyForInts(3.14f); // does not compile !
}
OK CASE DEMO NOK CASE DEMO
This utilizes the fact that a compiler instantiates a member function of a class template only when one is actually used (not when the class template is instantiated itself). And with the above solution, when a compiler tries to do so, it fails due to the execution of a static_assert
.
C++ Standard Reference:
§ 14.7.1 Implicit instantiation
[temp.inst]
Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[ Example:
template<class T> struct Z { void f(); void g(); }; void h() { Z<int> a; // instantiation of class Z<int> required Z<char>* p; // instantiation of class Z<char> not required Z<double>* q; // instantiation of class Z<double> not required a.f(); // instantiation of Z<int>::f() required p->g(); // instantiation of class Z<char> required, and // instantiation of Z<char>::g() required }
Nothing in this example requires
class Z<double>
,Z<int>::g()
, orZ<char>::f()
to be implicitly instantiated. — end example ]