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 function specialization of a templated class without specifying the class template parameter
You can use a technique called tag dispatch and replace the template specialisations by function overloads.
template<typename>
struct Tag {};
template <class A>
struct C3
{
void f_impl(Tag<int>) const;
void f_impl(Tag<char>) const;
template<class B>
void f() const {
f_impl(Tag<B>{});
}
};
struct D { static int g(void){ return 999; } };
template <class A>
void C3<A>::f_impl(Tag<int>) const { std::cout<<A::g()+1<<std::endl; }
template <class A>
void C3<A>::f_impl(Tag<char>) const { std::cout<<A::g()+2<<std::endl; }
Then your call site looks exactly as you want:
C3<D> c3; c3.f<int>(); // expect to see 1000
C3<D> c4; c4.f<char>(); // expect to see 1001
Full example here.
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 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
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.
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 do you specialize a member function inside a template class?
You can avoid writing any specializations, and use a type trait like std::is_pointer along with if constexpr
to decide what code to execute depending on the whether the type is a pointer type or not:
auto DoSomething(const T &t)
{
if constexpr (std::is_pointer_v<T>)
return new T(t->DoSomething(some_data));
else
return t.DoSomething(some_data);
}
If you don't want to check for whether T
is a pointer, but want to check something else, you can still use this pattern by dropping in a suitable replacement for is_pointer
.
C++ - specialize function template on a templated class with a non type template parameter
Partial template specializations are not allowed for function templates.
Use SFINAE or class templates
template <class T>
struct validateType : std::false_type {};
template <class A, A val, class B>
struct validateType<Foo<A, val, B>> : std::true_type {};
Edit:
Is this supposed to work for template functions as well?
NO. Partial template specializations are not allowed for function templates.
for template function, use SFINAE.
For example, this sample check weather T is unsigned integer type(C++17).
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, std::nullptr_t> = nullptr>
T foo(T n);
std::is_unsigned_v
was added in C++17. before C++17, usestd::is_unsigned<T>::value
.
https://en.cppreference.com/w/cpp/types/is_unsignedstd::enable_if_t
was added in C++14. before C++14, usetypename std::enable_if<con, T>::type
.
https://en.cppreference.com/w/cpp/types/enable_ifstd::nullptr_t
can hole only one value(nullptr
) so that I use it for SFINAE enabler.
(ja) https://qiita.com/kazatsuyu/items/203584ef4cb8b9e52462
However, in your case, you chould use class templates. It's simplest way to use class templates to check wether T is template class foo(BTW, not for template class foo, std::is_same
is simplest way).
Related Topics
How to Store Functional Objects with Different Signatures in a Container
Map Set/Get Requests into C++ Class/Structure Changes
Where Do I Find the Definition of Size_T
Advantages of Pass-By-Value and Std::Move Over Pass-By-Reference
What Is the Most Elegant Way to Read a Text File with C++
What Exactly Does Stringstream Do
Should I Use Virtual, Override, or Both Keywords
How to Choose Between Map and Unordered_Map
How to Tell Where a Header File Is Included From
C++ - Passing References to Std::Shared_Ptr or Boost::Shared_Ptr
How to Use Doxygen to Create Uml Class Diagrams from C++ Source
Differencebetween Wm_Quit, Wm_Close, and Wm_Destroy in a Windows Program
How Can Currying Be Done in C++
How to Reverse the Order of Arguments of a Variadic Template Function