Specialization of Templated Member Function in Templated Class

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 many is_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


  1. 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:


  1. 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:


  1. 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 by template<>. [..]

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 the template<> 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, use std::is_unsigned<T>::value.

    https://en.cppreference.com/w/cpp/types/is_unsigned
  • std::enable_if_t was added in C++14. before C++14, use typename std::enable_if<con, T>::type.

    https://en.cppreference.com/w/cpp/types/enable_if
  • std::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



Leave a reply



Submit