template class template method specialization - c++

Why does the following code fail to compile?
template <typename T>
struct X
{
template <typename R>
R default_value();
};
template <typename T>
int X<T>::default_value<int>()
{
return -1;
}
it says
x.cpp:17:30: error: template-id ‘default_value<int>’ in declaration of primary template
x.cpp:17:5: error: prototype for ‘int X<T>::default_value()’ does not match any in class ‘X<T>’
x.cpp:13:7: error: candidate is: template<class T> template<class R> R X::default_value()
I also tried to do
template <typename T>
template <>
int X<T>::default_value<int>()
{
return -1;
}
but this gives me another compilation error
prog.cpp:11: error: invalid explicit specialization before '>' token
prog.cpp:11: error: enclosing class templates are not explicitly specialized
prog.cpp:12: error: template-id 'default_value<int>' for 'int X<T>::default_value()' does not match any template declaration
I also tried doing the same for structures
template <typename T>
struct X
{
template <typename R> struct default_value;
};
template <typename T>
template <>
struct X<T>::default_value<int>
{
static int get() { return -1; }
};
same issue.
How to solve that?

One cannot explicitly specialize member templates. Consider:
template <class T>
struct X
{
template <class U> struct Y;
};
...Now (imagine we could do this):
template <class T>
template <>
struct X<T>::Y<int>
{};
...For X of which T are we explicitly specializing?
What if, after the point of definition of our explicit specialization, someone does this in one compilation unit...
void foo()
{
X<int>::Y<int> xy;
}
... and then this in another...(valid code, btw).
template <>
template<>
struct X<int>::Y<int>
{};
void foo()
{
X<int>::Y<int> xy;
}
... which would imply multiple definitions of the same class???
As mentioned previously, this is treated well here
Now, considering that the default value actually depends on the type T, perhaps one can get it from the type T.
template <class T>
struct X
{
static T defaultValue(){ return T::defaultValue(); }
};
or better yet, one could change the behavior of defaultValue based on whether T has the member defaultValue.

template <typename T>
template <>
int X<T>::default_value<int>()
{
return -1;
}
should be fine. Similar topic...

Related

Specializing templated function for a templated type?

I've got a function:
// declaration of random, specialize this to provide random instances of types
template <typename T> T random() {
static_assert(
std::is_void<T>::value && false, "random() not implemented for type"
);
}
I'd like to specialize it for another type, _point1d that's also templated:
template <typename T>
struct _point1d {
_point1d(T x) : x(x) {}
T x;
};
I tried this:
template <typename T>
_point1d<T> random<_point1d<T>>() { return _point1d<T>(random<T>()); }
But I get:
error: non-type partial specialization ‘random<_point1d<T> >’ is not allowed
With gcc. Is this possible?
You cannot specialize function templates partially.
The standard solution is to use an intermediate helper class template:
template <typename> struct Aux;
template <typename U> struct Aux<_point1d<U>>
{
static _point1d<U> f() { /* ... */ }
};
template <typename T> T random() { return Aux<T>::f(); }
// ^^^^^^^^^^^^^^^^^^^
That way you only have one single function template, and all the details of selecting the right specialization are done inside the class template, which you can freely specialize partially or explicitly as you choose.

template template parameter for stl containers behaving different from custom template class

I have the following struct and function
template <class T> struct C {};
template <template <class S> class T, class U> void f() { T<U> tu; }
when templating f() with C I do not get an error, when templating it with say std::vector I do.
int main() {
f<C, int>();
}
yields no errors
int main() {
f<std::vector, int>();
}
yields
error: no matching function for call to 'f'
f<std::vector, int>();
^~~~~~~~~~~~~~~~~~~~~~~~
note: candidate template ignored: invalid explicitly-specified argument for template parameter 'T'
template <template <class S> class T, class U> void f() { T<U> tu; }
What is the difference between C and std::vector here?
That's because vector has two template parameters, not one (T and Allocator).
You can either change your f template to accept two template parameters (or a variadic pack):
template <template <class...> class T, class U> void f() { T<U> tu; }
or you can alias vector to a 1-parameter template:
template<typename T>
using vec = std::vector<T>;
difference is that vector has two template parameters, not one. To fix this you may use
template <template <class... S> class T, class U> void f() { T<U> tu; }

Template specialization for a class which has multiple types

Class declaration is in a class.h file :
template <typename K, typename T>
class classx
{
...
unsigned int func1(K key);
...
which includes this class.hpp :
template <typename K, typename T>
unsigned int classx<K,T>::func1(K key)
{
return 1;
}
//Func1 for <int, typename T> ????
template <>
template <typename T>
unsigned int classx<int,T>::func1<int, T>(int key) // ERROR!
{
return 1;
}
This results:
error: expected initializer before ‘<’ token
What is the proper way of doing this?
Remove the second set of template parameters from your func1 definition and the template <>:
template <typename T>
unsigned int classx<int,T>::func1(int key)
{
return 1;
}
EDIT:
Additionally, you cannot partially specialize a single function of a template class. If you wish to do so, you will have to partially specialize the entire class.

Specialize templated function for templated class

In C++, I am trying to specialize a templated function for a object that is templated itself.
Here is a basic example:
test.h:
template <class T>
class myC {
T x;
};
template <class U>
void f(U y) {
}
template <>
template <class T>
void f<myC<T> >(myC<T> y) {
}
test.cpp
#include "test.h"
int main() {
myC<double> m;
f(m);
}
GCC 4.6.1 gives me the following error message:
In file included from test.cpp:1:0:
test.h:13:25: error: too many template parameter lists in declaration of ‘void f(myC<T>)’
test.h:13:6: error: template-id ‘f<myC<T> >’ for ‘void f(myC<T>)’ does not match any template declaration
test.h:13:25: note: saw 2 ‘template<>’, need 1 for specializing a member function template
Is this at all possible? Or is there another way to accomplish the same goal?
template <>
template <class T>
void f<myC<T> >(myC<T> y) {
}
What you're atttempting to be doing here is called partial specialization which is not allowed in case of function template.
A function template is either fully specialized, or not specialized at all. No partial specialization of function template is allowed by the language specification.
So you can overload the function template as:
template <class T>
void f(myC<T> y) //note that it is overload, not specialization
{
}
which is allowed, and preferred over even fully specialization of template.
Read these articles by Herb Sutter:
Why Not Specialize Function Templates?
Template Specialization and Overloading
You cannot specialize a template function; only template classes can be specialized. Edit: Nawaz's answer is correct: it's partial specialization that is not allowed for template functions, only for classes. A full specialization is possible:
template <class U> void f(U y) {}
template<> void f<double>(double y) {} // specialization for double
Note that the template argument need not be explicitly specified if it can be deduced from the context:
template<> void f<>(int y) {} // specialization for int
In your case, full specialization is not possible because the function argument is a template class. However, a template function, like any function, can be overloaded. In your case, it will be like this:
template <class T>
class myC {
T x;
};
template <class U>
void f(U y) {
}
template <class T>
void f(myC<T> y) {
}
int main() {
myC<double> m;
f(m);
return 0;
}
As far as I can tell, you cannot specialize template functions, only template classes (or structs).
But that is hardly a limitation: just declare a struct with static public member functions and mave the template parameters to the struct:
template <class T>
class myC {
T x;
};
template <class U>
struct Foo
{
static void f(U y) {
}
};
template <>
template <class T>
struct Foo<myC<T> >
{
static void f(myC<T> y) {
}
};
The drawback is that class templates do not solve the template parameters automatically. But that can be easlily solved with a function template, similar to the original one:
template <class U>
void f(U y) {
return Foo<U>::f(y);
}

Template specialization with a templatized type

I want to specialize a class template with the following function:
template <typename T>
class Foo
{
public:
static int bar();
};
The function has no arguments and shall return a result based on the type of Foo. (In this toy example, we return the number of bytes of the type, but in the actual application we want to return some meta-data object.)
The specialization works for fully specified types:
// specialization 1: works
template <>
int Foo<int>::bar() { return 4; }
// specialization 2: works
template <>
int Foo<double>::bar() { return 8; }
// specialization 3: works
typedef pair<int, int> IntPair;
template <>
int Foo<IntPair>::bar() { return 2 * Foo<int>::bar(); }
However, I would like to generalize this to types that depend on (other) template parameters themselves.
Adding the following specialization gives a compile-time error (VS2005):
// specialization 4: ERROR!
template <>
template <typename U, typename V>
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); }
I am assuming this is not legal C++, but why? And is there a way to implement this type of pattern elegantly?
Partitial specialization is valid only for classes, not functions.
Workaround:
template <typename U, typename V>
class Foo<std::pair<U, V> > {
public:
static int bar() { return Foo<U>::bar() + Foo<V>::bar(); }
};
If you does not want to specialize class fully, use auxiliary struct
template<class T>
struct aux {
static int bar();
};
template <>int aux <int>::bar() { return 4; }
template <>int aux <double>::bar() { return 8; }
template <typename U, typename V>
struct aux <std::pair<U, V> > {
static int bar() { return Foo<U>::bar() + Foo<V>::bar(); }
};
template<class T>
class Foo : aux<T> {
// ...
};
It is perfectly legal in C++, it's Partial Template Specialization.
Remove the template <> and if it doesn't already exists add the explicit class template specialization and it should compile on VS2005 (but not in VC6)
// explicit class template specialization
template <typename U, typename V>
class Foo<std::pair<U, V> >
{
public:
static int bar();
};
template <typename U, typename V>
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); }