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);
}
Related
I have a class, something like BizClass below. I'd like to define a templated function and a specialization for a particular concrete type. I'm not sure of the appropriate syntax.
template <class Foo>
class BizClass {
public:
template <typename Bar>
void Action(Container<Bar> m);
// Foo is used somewhere else...
};
// This seems to work.
template <class Foo>
template <typename Bar>
inline void BizClass<Foo>::Action(Container<Bar> m) {}
// This specialization doesn't compile, where Foobar is a concrete class.
template <class Foo>
inline void BizClass<Foo>::Action(Container<FooBar> m) {}
How do I handle the template specialization for this case?
In your first code sample titled This seems to work., that is just defining the body for the template function, it is not a specialization.
In the second sample you attempt to specialize a template which is a member of another unspecialized template. This is not allowed.
You need to also specialize BizClass if you want to specialize Action, e.g. here is an example with Foo=int and Bar=char:
template<> template<>
inline void BizClass<int>::Action(Container<char> m)
{
}
How do I handle the template specialization for this case?
As far I know, the C++ forbids specialization of a method, inside a template struct/class, without specializing the struct/class itself.
But you can use overloading: make Action (Container<FooBar> m) a not-template method
#include <iostream>
template <typename>
struct Container
{ };
struct FooBar
{ };
template <typename Foo>
struct BizClass
{
template <typename Bar>
void Action (Container<Bar> m);
void Action (Container<FooBar> m);
};
template <typename Foo>
template <typename Bar>
inline void BizClass<Foo>::Action (Container<Bar> m)
{ std::cout << "Action() generic version" << std::endl; }
template <typename Foo>
inline void BizClass<Foo>::Action (Container<FooBar> m)
{ std::cout << "Action() FooBar version" << std::endl; }
int main ()
{
BizClass<int> bci;
bci.Action(Container<int>{}); // print Action() generic version
bci.Action(Container<FooBar>{}); // print Action() FooBar version
}
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.
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...
Using MSVC++ 2010, defining a templated class member outside its declaration block:
template <typename T> class cls {
public:
template <typename T> void bar(T x);
};
template <typename T> void cls<T>::bar(T x) {}
yields:
unable to match function definition to an existing declaration
1> definition
1> 'void cls<T>::bar(T)'
1> existing declarations
1> 'void cls<T>::bar(T)'
why?
You need two template declarations because each construct works on a different template argument:
template <typename P>
template <typename T>
void cls<P>::bar(T x) {}
But it seems to me that bar does not need to be templated at all. Use this instead:
template <typename T>
class cls
{
public:
void bar(T x);
};
template <typename T> void cls<T>::bar(T x) {}
If you're intention is for bar to be a member template, then you need this:
template <typename T> class cls {
public:
template <typename U> void bar(U x);
};
template<typename T>
template<typename U>
void cls<T>::bar(U x) { }
Note that, the template parameter of the member must not shadow the class template parameter, hence I changed it to U.
Example:
template <typename T, typename U>
struct A {
void Print() {}
};
template <>
void A<int, float>::Print() {} // Okay
template <typename T>
void A<T, char>::Print() {} // Will produce error
Question:
I know that you have to define the class template partial specialization in the above code for it to work and I also know from the standard that The members of the class template partial specialization are unrelated to the members of the primary template (§ 14.5.5.3). However, why the difference in syntax between a explication specialization and a partial specialization?
You cannot specialize function templates partially, only fully.
The first instance makes use of the fact that member functions of class templates are themselves function templates, and thus the restriction applies to them.
When you partially-specialize the class template, you have an entirely new class template, which you have to define anew.
template <typename T>
void A<T, char>::Print() {} // Will produce error
You are:
re-defining a function (it has already been defined when declared void Print() {}, you see there are {}.
with a template argument list that doesn't match the declaration: template <typename T, typename U> void Print()
In fact, even if you haven't defined the function when declared it, you will still have an error since your declaration and definition do not match, the compiler will not be able to find a definition for the original template, or a declaration for the specialized template.
A specialized template function for a function that is related to a struct must have a specialized struct as well, This code works:
template <typename T, typename U>
struct A {
void Print() {}
};
template <>
void A<int, float>::Print() {} // Okay
template <typename T>
struct A<T,char>
{
void Print();
};
template <typename T>
void A<T,char>::Print() {}
Because template function has been declared in it's template struct.