C++ Template Partial Specialization Member Function

c++ template partial specialization member function

You cannot partially specialize only a single member function, you must partially specialize the whole class. Hence you'll need something like:

template <typename T>
class Object<T, 0>
{
private:
T m_t;
Object();
public:
Object(T t): m_t(t) {}
T Get() { return m_t; }
Object& Deform()
{
std::cout << "Spec\n";
m_t = -1;
return *this;
}
};

C++ Partial Template Specialization: Member Functions

A possible way is estract compute(), create a base class only for it and specialize this base class.

I mean... if you create a generic version and two specializations for fooSub

template <int a, int b>
struct fooSub
{
void compute ()
{ std::cout << "- foo generic compute()" << std::endl; }
};

template <int a>
struct fooSub<a, 2>
{
void compute ()
{ std::cout << "- foo compute() for 2" << std::endl; }
};

template <int a>
struct fooSub<a, 3>
{
void compute ()
{ std::cout << "- foo compute() for 3" << std::endl; }
};

you can "specialize" compute in foo through inheritance simply as follows

template <int a, int b>
struct foo : public fooSub<a, b>
{ };

Another possible solution, if you can use at least C++11, is activate/deactivate different version of compute() using SFINAE (std::enable_if) as in the following bar class

template <int a, int b>
struct bar
{
template <int bb = b>
typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
compute ()
{ std::cout << "- bar generic compute()" << std::endl; }

template <int bb = b>
typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
{ std::cout << "- bar compute() for 2" << std::endl; }

template <int bb = b>
typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
{ std::cout << "- bar compute() for 3" << std::endl; }
};

Follows a full compilable example for both ways

#include <iostream>
#include <type_traits>

template <int a, int b>
struct fooSub
{
void compute ()
{ std::cout << "- foo generic compute()" << std::endl; }
};

template <int a>
struct fooSub<a, 2>
{
void compute ()
{ std::cout << "- foo compute() for 2" << std::endl; }
};

template <int a>
struct fooSub<a, 3>
{
void compute ()
{ std::cout << "- foo compute() for 3" << std::endl; }
};

template <int a, int b>
struct foo : public fooSub<a, b>
{ };

template <int a, int b>
struct bar
{
template <int bb = b>
typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
compute ()
{ std::cout << "- bar generic compute()" << std::endl; }

template <int bb = b>
typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
{ std::cout << "- bar compute() for 2" << std::endl; }

template <int bb = b>
typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
{ std::cout << "- bar compute() for 3" << std::endl; }
};


int main()
{
foo<0, 1>{}.compute(); // print - foo generic compute()
foo<1, 2>{}.compute(); // print - foo compute() for 2
foo<2, 3>{}.compute(); // print - foo compute() for 3

bar<2, 1>{}.compute(); // print - bar generic compute()
bar<3, 2>{}.compute(); // print - bar compute() for 2
bar<4, 3>{}.compute(); // print - bar compute() for 3
}

Partial specialization of specific member functions

Tag-dispatch the call to update:

template <typename> struct tag {};

template <typename T1, typename T2>
class B
{
public:
void update()
{
return update(tag<B>());
}

private:
template <typename U1>
void update(tag<B<U1, int> >)
{
// specialization
}

template <typename U1, typename U2>
void update(tag<B<U1, U2> >)
{
// normal
}
};

DEMO

c++ class template partial specialization without specializing all member functions

In my experience use inheritance method (2) when you actually want a new class that inherits from the template. Use method (1) when the partial specialization is sufficiently different from the general case or general case is not defined at all and you just declare a bunch of partial specializations to make use of SFINAE.

If you simply want to enable/disable methods of a class based on template parameters then utilize SFINAE. As this way you can centralize all your definitions in one place and reason about them more easily. This is the preferred method unless you want user to make the template specializations on their own - which isn't desirable in general.

Example of SFINAE:

template <class T, size_t N>
class X {
public:
void a() {...};
X<T, N> b(X<T, N> x);
// etc
static X<T, n> c() {...};

template<size_t uN = N, std::enable_if_t<uN==3,int>=0>
void d() {...};
protected:
T data[N];
};

Here, X<int,3> x; x.d(); will compile but X<int,2> x; x.d(); will not as d() method is disabled unless N==3.

You can read a lot more about usages of SFINAE in template functions and classes in numerous online guides (note that the syntax is quite different for functions and classes).

How to implement full specialization templates member function within partial specialization templates class

[temp.expl.spec]/17:

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. In such an explicit specialization declaration, the keyword template followed by a template-parameter-list shall be provided instead of the template<> preceding the explicit specialization declaration of the member. The types of the template-parameters in the template-parameter-list shall be the same as those specified in the primary template definition.

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.

for your code:

template<typename A, typename B>
class Foo{
public:
template<typename C> void bar();
};

template<typename T> // for `Foo`
template<> // for `bar`
inline void Foo<T, int>::bar<float>(){}

int main(){
Foo<double, int> foo;
foo.bar<float>();
return 0;
}

it's ill-formed because bar is explicitly specialized but Foo is NOT.

c++ partial specialization of template class member functions

if you can change the implementation of static void switch_storage_order(matrix_type& m), you may use something like:

// By default can't change storage order so simply transpose.
static void switch_storage_order(matrix_type& m) { transposer<matrix_type>()(m); }

with

// generic case
template <typename T>
struct transposer {
void opearator () (T& m) const { m.transpose(); }
};

// your specialization.
template<typename T>
struct transposer<ublas::matrix<T>> {
void opearator () (ublas::matrix<T>& m) const { m = boost::numeric::ublas::trans(m); }
};

Partial member function template specialisation and data member access

As commented, you don't need to use partial specialization for this at all, indeed partial specialization is usually pretty easy to avoid, and preferred to avoid.

private:
template <class T>
struct tag{}; // trivial nested struct

template <class I, class T>
void push_impl(I first, I last, tag<T>) { ... } // generic implementation

template <class I, class T>
void push_impl(I first, I last, tag<std::complex<T>>) { ... } // complex implementation

public:
template <class InputIt>
void push(InputIt first, InputIt last)
{
push_impl(first, last,
tag<typename std::iterator_traits<InputIt>::value_type> {});
}

Since push_impl is a (private) member function you don't need to do anything special any more.

Compared to your proposed solutions, this has no extra performance cost. It's the same number of function calls, the only difference is passing a stateless type by value, which is a wholly trivial optimization for the compiler. And there's no sacrifice in encapsulation either. And slightly less boilerplate.

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)



Related Topics



Leave a reply



Submit