Templated Class Specialization Where Template Argument Is a Template

Templated class specialization where template argument is a template

It's possible to specialize the class like this

template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t) { /* something */ }
};

It's not possible to specialize just the member method, because the specialization is on the class as a whole, and you have to define a new class. You can, however, do

template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t);
};

template <>
template <typename T,typename S>
void MyTemplateClass<SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S>& t)
{
// something
}

to split up the declaration and definition.

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).

How to specialize a class template with a template template parameter?

The following code compiles fine:

#include <type_traits>

template <typename T>
struct X {};

// primary template, no template template parameter
template<typename T>
struct Z : std::false_type {};

// specialization on the template template parameter with arbitrary T
template<typename T>
struct Z<X<T>> : std::true_type {};

// here's where you need the template template parameter
template <template<class> class C>
struct Z<C<int>> : std::true_type {};

int main()
{
static_assert(!Z<Z<double>>::value, "" );
static_assert( Z<Z<int >>::value, "" );
static_assert( Z<X<double>>::value, "" );
// static_assert( Z<X<int >>::value, "" ); // error: ambiguous
// partial specialization
}

In your code you give Z a template template parameter, even though that should be done for the specialization only. That's why your code does not compile.

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 Specialisation with Template Argument

For C++11 you can SFINAE enable/disable (using std::enable_if) two differents versions of foo() inside a not specialized Foo class.

In C++98 you don't have std::enable_if but you can simulate it (give me some minutes and I try to propose an example). Sorry: my idea doesn't works because this method require the use of default template arguments for methods that is a C++11 innovation.

Another way is define a template base class for Foo(), say FooBase, insert foo() (and only foo()) in FooBase and specialize FooBase.

Another way, that works also with C++98, can be tag dispatching: you can define an unique foo(), with zero parameter, that call another foo(), with a parameter that is determined by T.

The following is a full (C++98 compilable) example

#include <iostream>

struct barWay {};
struct noBarWay {};

template <int>
struct Bar
{ };

template <typename>
struct selectType
{ typedef noBarWay type; };

template <int N>
struct selectType< Bar<N> >
{ typedef barWay type; };

template <typename T>
struct Foo
{
void foo (noBarWay const &)
{ std::cout << "not Bar version" << std::endl; }

void foo (barWay const &)
{ std::cout << "Bar version" << std::endl; }

void foo ()
{ foo(typename selectType<T>::type()); }
};

int main ()
{
Foo<int> fi;
Foo< Bar<42> > fb;

fi.foo();
fb.foo();
}

Templated function template specialization

A partial specialization is when you specify part of the type of the template, but not the whole thing. For example,

template <>
template<class T> set<T> convertTo<set<T>>(const char* str)

would partially specialize for set<T> if partial function specialization were allowed.

The two main ways of handling this are to instead overload, by removing the template<> part, or better yet switch to using template class specialization. The problem with overloading is that it looks somewhat different if you are overloading with another template (as with set<T>) or with a single type (as with int), and mixing specialization and overload almost certainly doesn't work as you expect.

Therefore, template class specialization is usually the best way to go, and can be done like this:

// Generic version
template <typename T>
class Converter {
public:
T operator() (const char* str) {
T output;
stringstream ss(str, stringstream::in);
ss >> output;
return output;
}
};

template <>
class Converter<int> {
public:
int operator() (const char* str) {
return atoi(str);
}
};

// ...

template <typename T>
T convertTo(const char* str) {
return Converter<T>{}(str);
}

That way you can use any type of specialization you want for the class without issue.

Specialize template class constructor on templated template parameter

A C++11 solution could be based on SFINAE: enabling the first or the second constructor if U is a S based type or not.

To make this, can be useful develop a type traits to detect if a type is (or isn't) S based; by example

template <typename>
struct isS : public std::false_type
{ };

template <typename T>
struct isS<S<T>> : public std::true_type
{ };

With isS, you can write your constructors (in the body of the A class) as follows

template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }

template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }

If you need the template argument of S, you can define the specialization of isS as follows

template <typename T>
struct isS<S<T>> : public std::true_type
{ using type = T; };

and use it as typename isS<V>::type.

A full working example

#include <vector>
#include <iostream>
#include <type_traits>

template <typename T>
struct S
{
S (T const &, bool, bool)
{ std::cout << "S constructor" << std::endl; }
};

template <typename>
struct isS : public std::false_type
{ };

template <typename T>
struct isS<S<T>> : public std::true_type
{ };

template <typename T, typename U>
struct A : public U
{
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }

template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
};

int main ()
{
long l { 0L };

// print "generic A constructor"
A<long, std::vector<int>> alv(l, true);

// print "S constructor>" and "S specific A constructor"
A<long, S<int>> als(l, true);
}


Related Topics



Leave a reply



Submit