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.
Related
Are explicit instantiations of template functions allowed before the definition of the function, if a declaration occurs first?
E.g., is the following allowed:
// declaration
template <typename T>
void foo(T param);
// explicit instantiation
template void foo<int>(int);
// definition of primary template
template <typename T>
void foo(T param) {}
In general it seems to compile, but of course that is only a mild indication as to whether it is allowed or not.
There is nothing that explicitly forbids it in [temp.explicit]. Furthermore, there is an explicit statement ([temp.explicit#5]):
A declaration of a function template, a variable template, a member function or static data member of a class template, or a member function template of a class or class template shall precede an explicit instantiation of that entity.
If a definition was required, this paragraph would be different (i.e., it will require a definition), thus your code seems legal.
Consider the following template class
template<typename T>
struct Caller {
void func(const T &t) { t.func(); }
void gunc(const T &t) { t.gunc(); }
};
Now let some class Target only provide the member function func() but not gunc(), i.e.
struct Target {
void func() const { /* ... /* }
};
is the template instantiation Caller<Target> valid?
GCC, clang as well as VC++ accept such template instantiations. Of course, calling Caller<Target>::gunc() leads to an error but Caller<Target>::func() works just fine and as intended.
Now the question: What is the background for this permissive behavior and where are the relevant paragraphs in C++ standard.
It's specified in the standard, under Templates (14), Template instantiation and specialization (14.7), Implicit instantiation (14.7.1).
3 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.
And
11 An implementation shall not implicitly instantiate a function
template, a member template, a non-virtual member function, a member
class, or a static data member of a class template that does not
require instantiation.
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
Given the following class
template <class T>
class A {
static const B<T> member;
};
how can I instantiate member for each class A<T> separately?
Simple. As you would with any other static non-integral type.
template <class T>
class A {
static const B<T> member;
};
template <class T>
const B<T> A<T>::member/*(optional-args)*/;
In order to allocate member differently for different types of T, you must use template specialisation.
To start the template specialisation you must use this syntax:
template<>
// ... explicit definition
The syntax for the explicit definition is basically the same syntax as:
template <class T>
const B<T> A<T>::member/*(optional-args)*/;
Except, instead of template <class T>, you use template<>, and where T is, you put the actual type.
For example:
template<>
const B<type> A<type>::member(args);
NOTE: If you wish to call the default constructor with template specialisation in this scenario, please see the EDIT below.
You can substitute type for any type you wish. With this you can provide different arguments for each possible type. Although if you specialise too much, you should consider if your design is really suited to use templates.
Here it is in action (online), feel free to clone and play around with it.
I thought I'd mention that the declaration must be where the template class is located. In other words, if A is declared in the header, you must also declare the allocation for member in the header file. You can alternatively use an inline file (.inl) and #include the .inl file in the header file that the template class is declared.
EDIT:
It seems that in C++98, the following syntax to call the default constructor does not compile under GCC or clang, if you refer to the member variable:
template <>
const B<type> A<type>::member/*()*/;
Where type is any type.
However the following does:
template <class T>
const B<T> A<T>::member/*()*/;
I'm not sure if this is a bug, or just incorrect syntax.
I recommend instead to do the following:
template <>
const B<type> A<type>::member = B<type>();
Or if you are using C++11, you can use curly brackets to call the default-constructor, like so:
template <>
const B<type> A<type>::member{};
If you use regular brackets, the compiler will thing it is a static function within the A<type> class, and if you use no brackets, you will get an undefined reference to 'A<type>::member' linker error. Which you can see here.
Here is the discussion that Aaron and I discovered this error.
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.