explicit specialization of template class member function
It doesn't work that way. You would need to say the following, but it is not correct
template <class C> template<>
void X<C>::get_as<double>()
{
}
Explicitly specialized members need their surrounding class templates to be explicitly specialized as well. So you need to say the following, which would only specialize the member for X<int>
.
template <> template<>
void X<int>::get_as<double>()
{
}
If you want to keep the surrounding template unspecialized, you have several choices. I prefer overloads
template <class C> class X
{
template<typename T> struct type { };
public:
template <class T> void get_as() {
get_as(type<T>());
}
private:
template<typename T> void get_as(type<T>) {
}
void get_as(type<double>) {
}
};
Template member specialization in template class
If we look at n4810 § 13.8.3
- A member function, a member function template, a member class, a
member enumeration, a member class template, a static data member, or
a static data member template of a class template may be explicitly
specialized for a class specialization that is implicitly
instantiated; in this case, the definition of the class template shall
precede the explicit specialization for the member of the class
template. If such an explicit specialization for the member of a class
template names an implicitly-declared special member function
(11.3.3), the program is ill-formed.
You are however allowed to do this, where both are specialized:
template<typename U>
struct A
{
template<typename... Ts> auto func() { /* ... */ }
};
template <>
template <>
auto A<int>::func<int>()
{
// ok, enclosing class template explicitly specialized
}
While this is invalid c++:
template <typename U>
template <>
auto A<U>::func<int>()
{
// ops: invalid, enclosing class template not explicitly specialized
}
According to:
- 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.
And because of:
- A declaration of a function template, class template, or variable
template being explicitly specialized shall precede the declaration of
the explicit specialization.
Therefore this should not be inside the outer template declaration:
template <typename U>
struct A {
template<typename...Ts> auto func();
template<> auto func<int>() { return std::string{"foo"}; } // should not work
};
I do not know why clang permits this.
But it is allowed to be in the namespace scope where the primary template was declared, in this case global namespace scope.
explicit specialization of template class member function
Unfortunately a template
method inside a template
class cannot be specialized just based on template
argument of method.
You need to specialize the template class
also. In other words, the member method specialization should be a complete specialization with respect to class template
(i.e. <T,U>
) params as well as the member template
params (i.e. <size_t>
).
For example, you may have to specialize something like this (demo):
template<> // <------ you have to specialize class also
template<>
inline void A<int, double>::BindValues<1>() // <-------- see A<T,U>
{
...
}
Explicit specialization of member function template in source file
Declaring specializations in a source file and can cause all sorts of subtle issues that are very difficult to diagnose. The compiler isn't obligated to help you in any regard here either. The standard strongly encourages you not to do this, with the help of a limerick, in [temp.expl.spec]/6-7:
If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program
does not provide a definition for an explicit specialization and either the specialization is used in a way
that would cause an implicit instantiation to take place or the member is a virtual member function, the
program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit
specialization that is declared but not defined.The placement of explicit specialization declarations for function templates, class templates, variable templates,
member functions of class templates, [...], etc., can affect whether a program is well-formed according
to the relative positioning of the explicit specialization declarations and their points of instantiation
in the translation unit as specified above and below. When writing a specialization, be careful about its
location; or to make it compile will be such a trial as to kindle its self-immolation.
It's likely that in some translation units, the specialization happened to be declared before the first use - and in some translation units it hasn't been. It's better to avoid all such issues entirely by simply declaring your specialization in your header:
// writer.h
class Writer {
public:
...
template <typename T, typename V>
void addField(const std::string& name, V v)
{ /* ... */ }
};
// still writer.h
template <>
inline void Writer::addField<some_type, int>(const std::string& name, int v)
{ /* ... */ }
You can also just declare it in the header (no longer needs to be inline), and still define it in the source.
Template member function specialization in a template class
Why does this member function specialization get error?
When you instantiate the template class A
for example A<std::vector<int>>
, the template parameter T
is equal to std::vector<int>
, not std::vector<T>
, and this a specialization case of the function. Unfortunately this can not be done with member functions as mentioned in the comments.
Are there some better solutions?
Yes; In c++17 you could use if constexpr
with a trait to check the std::vector
, like this.
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
void print() const /* noexcept */
{
if constexpr (is_std_vector<T>::value) // when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else // for types other than `std::vector<>`
{
std::cout << mData << std::endl;
}
}
};
(See Live Online)
This way you keep only one template class and the print()
will instantiate the appropriate part according to the template type T
at compile time.
If you don not have access to C++17, other option is to SFINAE the members(Since c++11).
#include <type_traits> // std::false_type, std::true_type, std::enbale_if
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
template<typename Type = T> // when T == `std::vector<>`
auto print() const -> typename std::enable_if<is_std_vector<Type>::value>::type
{
for (const auto element : mData)
std::cout << element << "\n";
}
template<typename Type = T> // for types other than `std::vector<>`
auto print() const -> typename std::enable_if<!is_std_vector<Type>::value>::type
{
std::cout << mData << std::endl;
}
};
(See Live Online)
What if I have more other data types like self-define vector classes
or matrices? Do I have to define manyis_xx_vector
?
You can check the type is a specialization of the provided one like as follows. This way you can avoid providing many traits for each type. The is_specialization
is basically inspired from this post
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// custom MyVector (An example)
template<typename T> struct MyVector {};
template<typename Test, template<typename...> class ClassType>
struct is_specialization final : std::false_type {};
template<template<typename...> class ClassType, typename... Args>
struct is_specialization<ClassType<Args...>, ClassType> final : std::true_type {};
And the print
function could be in c++17:
void print() const /* noexcept */
{
if constexpr (is_specialization<T, std::vector>::value)// when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else if constexpr (is_specialization<T, ::MyVector>::value) // custom `MyVector`
{
std::cout << "MyVector\n";
}
else // for types other than `std::vector<>` and custom `MyVector`
{
std::cout << mData << std::endl;
}
}
(See Live Online)
How do I define an explicit specialization of a template member function in .cpp file
I'm not sure, but I think you're trying to do this.
In Foo.h
struct Color {};
class Foo
{
public:
template<typename T> int add(T b);
};
// declare, but do not implement, specialization
template<>
int Foo::add<Color>(Color c);
// general implementation
template<typename T>
int Foo::add(T b)
{
return 0;
}
In Foo.cpp
#include "Foo.h"
// explicitly implement
template<>
int Foo::add<Color>(Color b)
{
return 42;
}
Finally, main.cpp
#include "Foo.h"
int main()
{
Foo f;
std::cout << f.add(Color()) << '\n';
}
Output
42
template class - member function specialization
Not compliantly, it doesn't.
FWIW, GCC 4.8 rejects your code without the template <>
.
Your compiler is either buggy or has an extension to support this; I can confirm that MSVS 2012 accepts the code. I'm told that MSVS 2013 November CTP also eats it up without complaint. To be fair, Visual Studio was always fairly lenient about template specifications.
[C++11: 14.7/3]:
An explicit specialization may be declared for a function template, a class template, a member of a class template or a member template. An explicit specialization declaration is introduced bytemplate<>
. [..]
The only exception to this rule is:
[C++11: 14.7.3/5]:
[..] Members of an explicitly specialized class template are
defined in the same manner as members of normal classes, and not using thetemplate<>
syntax. [..]
… but that does not apply here.
How to specialize template member function?
As Igor mentioned, you can implement the generic version in the header file, and then the specialization in the cpp file, for example:
// MyStruct.h
struct MyStruct {
// ...
template <typename T>
void readField(std::istream& in, T& data) {
read(in, data);
data = ntohl(data);
}
};
Then in the cpp file you can implement the specialization, for example:
// MyStruct.cpp
template <>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data) {
read(in, data);
}
Update: After reading the comments, the specialization can also be in the same header file as the primary template, but not within the struct, for example (I verified this by compiling and running a similar example without error):
// MyStruct.h
struct MyStruct {
// ...
template <typename T>
void readField(std::istream& in, T& data) {
read(in, data);
data = ntohl(data);
}
};
template <>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data) {
read(in, data);
}
// End MyStruct.h
Related Topics
C++ Obtaining Milliseconds Time on Linux - Clock() Doesn't Seem to Work Properly
Why Can't I Have a Non-Integral Static Const Member in a Class
Linux: Executing Child Process With Piped Stdin/Stdout
Sfinae to Check For Inherited Member Functions
Checking If a Directory Exists in Unix (System Call)
Createprocess from Memory Buffer
Dual Emission of Constructor Symbols
Rand() % 14 Only Generates the Values 6 or 13
C++ Get Name of Type in Template
C/C++ Unsigned Integer Overflow
How to Get Double Quotes into a String Literal
Difference Between Static, Auto, Global and Local Variable in the Context of C and C++