So I've got a class that wants to instantiated for exactly one of two classes. I declare it in the header:
template <class T>
class MyClass {
public:
bool DoSomethingGeneric();
bool DoSomethingTSpecific();
};
Since I don't want to place the method definitions in the header, I instead place them in the implementation file, and perform an explicit specialization. While the DoSomethingGeneric method can be defined generically using a template, the DoSomethingTSpecific requires two separate implementations, one for each of the two possible classes for which I want to instantiate MyClass:
template <class T>
bool MyClass<T>::DoSomethingGeneric() {
// Generic code
}
template <>
bool MyClass<ClassA>::DoSomethingTSpecific() {
// ClassA-specific implementation
}
template <>
bool MyClass<ClassB>::DoSomethingTSpecific() {
// ClassB-specific implementation
}
Now, riddle me this: where do I place the explicit specialization? If I place it after my template definitions (like I usually do with specializations of purely-generic classes), clang says:
explicit specialization of 'MyClass<ClassA>' after instantiation
This message is accompanied by a pointer to the line where DoSomethingTSpecific is defined. This makes sense. My understanding is that the explicit specialization of the DoSomethingTSpecific method counts as an implicit specialization.
Meanwhile, if I place the specializations after all the template definitions, I see:
no function template matches function template specialization 'DoSomethingTSpecific'
This one is kind of a mystery to me.
Any thoughts? How can I have an explicit class-level specialization and explicit method specialization?
From the C++ Standard §14.7.3(5) Explicit specialization (emphasis mine):
Members of an explicitly specialized class template are
defined in the same manner as members of normal classes, and not using the template<> syntax.
Example:
template <> // specialization for classA
class MyClass<ClassA> {
public:
bool DoSomethingTSpecific(); // must be declared here
};
// template<> is not used here
bool MyClass<ClassA>::DoSomethingTSpecific() {
// ClassA-specific implementation
}
Demo:
http://cpp.sh/3tc2g
Related
I'm trying to use templates, but couldn't understand what is wrong with below code.
solve.h
#include "nlp.h"
#include "Ipopt_solve.h"
enum algo_type {IPOPT =1, SQP};
template<int ALG>
class solve
{
public:
solve()
{
}
};
template<>
class solve<IPOPT>
{
public:
solve(nlp*);
private:
Ipopt_solve m_ipopt;
};
solve.cpp
template<>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
Ipopt_solve is a sub-class of an abstract class TNLP. Ipopt_solve is initialized with a reference to nlp class.
from main.cpp
nlp problem(&model);
solve<IPOPT> solution(&problem);
I'm getting the error like shown below.
error: template-id 'solve<>' for 'solve<1>::solve(nlp*)' does not match any template declaration
solve::solve(nlp* problem): m_ipopt(problem)
This declaration in its original form
template<>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
is formally valid by itself. However, it is not doing what you think it is doing. This declaration declares an explicit specialization for a member of the main template
template<int ALG>
class solve
{
...
It has no relation to your explicit specialization
template<>
class solve<IPOPT>
{
...
The compiler is trying to specialize constructor solve<ALG>::solve(nlp* problem) of the main template. However, the main template has no such constructor. Hence the error message, that tells you exactly that: the compiler does not understand what constructor you are trying to specialize, it cannot find the matching member in the main template.
For example, you can use this syntax to explicitly specialize the default constructor of the main template
template<>
solve<SQP>::solve()
{
// Specialized code for `solve<SQP>`'s default constructor
}
This will compile fine since the main template does indeed have such constructor. (Note that you don't have to explicitly specialize the whole class for that, you can just explicitly specialize the constructor.)
Your intent was, obviously, completely different: to provide definition for the constructor in the class template specialization
template<>
class solve<IPOPT>
{
...
The proper syntax for that should not mention template<>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
You should remove template<>, i.e.
// template <>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
template<> is used for template specialization (for a template); but you're just defining a non-template member function (of a class template specialization). (That's why the compiler complains that the template declaration can't be found.)
Is it possible to explicit instantiate one or more specializations of a template function?
Second, does it matter if the function is a class member?
Is it legal C++11 and also is it accepted by compilers so it doesn't come with problems?
Is it possible to explicit instantiate one or more specializations of a template function?
Yes, however,
[temp.explicit]/5:
For a given set of template arguments, if an explicit instantiation of a template appears after a declaration of an explicit specialization for that template, the explicit instantiation has no effect.
Second, does it matter if the function is a class member?
No, AFAIK;
[temp.explicit]/1:
A class, a function or member template specialization can be explicitly instantiated from its template. A member function, member class or static data member of a class template can be explicitly instantiated from the member definition associated with its class template. An explicit instantiation of a function template or member function of a class template shall not use the inline or constexpr specifiers.
Example from [temp.explicit]/3:
template<class T> class Array { void mf(); };
template class Array<char>;
template void Array<int>::mf();
template<class T> void sort(Array<T>& v) { /∗ ... ∗/ }
template void sort(Array<char>&); // argument is deduced here
namespace N {
template<class T> void f(T&) { }
}
template void N::f<int>(int&);
Is it legal C++11 and also is it accepted by compilers so it doesn't come with problems?
Well, yes, but for libraries there's always the problem of ABI compatibility; especially if different compilers have been used for library and library user (e.g. program including that library). The C++ Standard does not specify an ABI.
template<typename T>
struct A{
void method1(){}
};
template<>
struct A<int>{
void method2(){}
};
Will A<int> have both method1 and method2? And A<float> will only have method1 ?
Each specialization brings an entirely new data type into existence (or an entirely new template, if the specialization is only partial). From the Standard (C++11):
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
And:
(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
The above is stated in the context of partial specializations, but it applies to explicit specializations (as in your case) as well, although the Standard does not say this very clearly.
Also note that you need not only declare all member functions that you want in a specialization, but you need to define them, too (here, the Standard is very clear even about explicit specializations):
(14.7.3/5) A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the class template; instead, the member of the class template specialization shall itself be explicitly defined if its definition is required. In this case, the definition of the class template explicit specialization shall be in scope
at the point at which the member is defined. The definition of an explicitly specialized class is unrelated to the definition of a generated specialization. That is, its members need not have the same names, types, etc. as the members of a generated specialization. [...]
So, indeed, A<int> will only have method2(), and A<float> will only have method1() as member. Furthermore, if you were to introduce method1() in the A<int> specialization as well, it needs not have the same argument types or return type as A<float>::method1().
See #aschepler's answer for possible ways to avoid having to rewrite the template definition for the int case.
#jogojapan's answer explains what the language does. Here's a couple workarounds if you do want to add new members for a specific specialization:
template<typename T>
struct A_Base {
void method1() {}
};
template<typename T>
struct A : public A_Base<T> {};
template<>
struct A<int>
: public A_Base<int>
{
void method2() {}
};
Now A<int> has members method1 and method2, but A<float> has no method2.
OR (if you can modify the primary template)...
#include <type_traits>
template<typename T>
struct A {
void method1() {}
template<int N=0>
auto method2() ->
typename std::enable_if<std::is_same<T, int>::value && N==N>::type
{}
};
The template<int N> and N==N parts make sure std::enable_if has a dependent value and therefore doesn't complain until somebody actually tries to use A<T>::method2 with an incorrect T parameter.
And since this question and answer seem to still be getting attention, a much later edit to add that in C++20, you can simply do:
#include <type_traits>
template<typename T>
struct A {
void method1() {}
void method2() requires std::is_same_v<T, int> {}
};
The specialisation replaces the generic template. So A<int> will only have method2() and, of course, A<double> will only have method1().
Look at the code:
template <class x> struct Foo
{
int getX(x *p) { return(0); }
enum E12 { a };
};
template <> int Foo<int>::getX(int*)
{
return(-15);
}
template <> enum Foo<int>::E12
{
a, b, c
}
As it was discussed in Cannot overload function, the first specialization is legal and even works in MSVC. While the second specialization for enum does not even want to compile, saying "error C2988: unrecognizable template declaration/definition".
It seems to me that C++ is making relaitively unlogical exception for methods. Enum is just an example. The same thing can be applied to member classes, typedefs, etc.
I will be happy is some body will comment on this.
This is a very obscure new feature of C++11. File a bug report with Microsoft, although it is unlikely it will be given priority as almost nobody is aware this is allowed. The correct syntax would be
template <class x> struct Foo
{
int getX(x *p) { return(0); }
enum E12 { a };
};
template <> int Foo<int>::getX(int*)
{
return(-15);
}
template <> enum Foo<int>::E12
{
a, b, c
};
I've filed a bug with GCC. Can someone test on recent Clang?
In C++03, only classes and functions may be explicitly specialized. From the standard, C++03 14.7.3/1:
An explicit specialization of any of the following:
function template
class template
member function of a class template
static data member of a class template
member class of a class template
member class template of a class or class template
member function template of a class or class template
can be declared by a declaration introduced by template<>
A member enum is not such a case. (Generally speaking, an enum type is always defined only once at its first declaration.)
To obtain a templated enum or typedef, you can wrap it in a class template. In your case, it would be a member class template of Foo. Such a construct is called a metafunction.
C++11 also has alias templates, which are like templated typedefs, but they cannot be explicitly specialized.
The policy of only allowing classes and functions to be specialized, and then allowing such templates to encapsulate other things like enum and typedef, seems more consistent to me than allowing direct specialization of enum. But, perhaps the language is going in your preferred direction.
I know this subject should be pretty much dated by now, but I'm having a tough time with this specific case.
Straight to the point, this is what I want to do:
enum MyEnum
{
E_1,
E_2
};
template <MyEnum T>
class MyClass
{
// method to be fully specialized
template <typename U>
void myMethod(U value);
};
// full specialization of method template from class template
// (or is this in fact partial, since I'm leaving T alone?)
template <MyEnum T>
template <>
void MyClass<T>::myMethod<int>(int value)
{
std::cout << value << '\n';
}
Is this possible?
C++03 [$14.7.3/18] says
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
So you need to specialize the enclosing class too.
Something like this would work.
template <>
template <>
void MyClass<E_1>::myMethod<int>(int value)
{
std::cout << value << '\n';
}
Since you leave T, while specializing only function template, then what you're trying to do would be called partial specialization, because T is still templated and you can use it in your function. But unfortunately, partial template specialization of function (whether be it member function or non-member function) is not allowed. So your code would give compilation error.
Either you fully specialize by specializing the class template as well, or you don't at all.