Template Specialization for Multiple Types

Template specialization for multiple types

You need your remap trait to simply map from input types to output types, and have your foo<T>(int) interface function delegate to a foo_implementation<remap<T>::type>(int) implementation. i.e.:

template <typename T>
struct remap {
// Default: Output type is the same as input type.
typedef T type;
};

template <>
struct remap<char> {
typedef unsigned char type;
};

template <>
struct remap<signed char> {
typedef unsigned char type;
};

template <typename T>
void foo_impl(int x);

template <>
void foo_impl<unsigned char>(int x) {
std::cout << "foo_impl<unsigned char>(" << x << ") called\n";
}

template <typename T>
void foo(int x) {
foo_impl<typename remap<T>::type>(x);
}

See it live at ideone.com.

That said, it might be realistically simpler to define foo_char, foo_int and foo_short and just call the correct one from client code. foo<X>() isn't syntactically much different from foo_X().

Class Template specialization for multiple types

You can use partial template specialization in combination with SFINAE to achieve this:

#include <type_traits>

template <class T, typename = void>
class State
{
T state;

public:
void set(T newState)
{
state = newState;
}

T get()
{
return state;
}
};

template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
T state;

public:
void set(int newState)
{
state = newState;
}

int get()
{
return state;
}

int multiplyState(int n)
{
return state*n;
}
};

live example here

The trick here lies in the use of the second template parameter (which can be unnamed and is given a default argument). When you use a specialization of your class template, e.g., State<some_type>, the compiler has to figure out which of the templates should be used. To do so, it has to somehow compare the given template arguments with each template and decide which one is the best match.

The way this matching is actually done is by trying to deduce the arguments of each partial specialization from the given template arguments. For example, in the case of State<int>, the template arguments are going to be int and void (the latter is there because of the default argument for the second parameter of the primary template). We then try to deduce the arguments for our sole partial specialization

template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>;

from the template arguments int, void. Our partial specialization has a single parameter T, which can directly be deduced from the first template argument to be int. And with that, we're already done as we have deduced all parameters (there is only one here). Now we substitute the deduced parameters into the partial specialization: State<T, std::enable_if_t<std::is_arithmetic_v<T>>>. We end up with State<int, void>, which matches the list of initial arguments of int, void. Therefore, the partial template specialization applies.

Now, if, instead, we had written State<some_type>, where some_type is not an arithmetic type, then the process would be the same up to the point where we have successfully deduced the parameter for the partial specialization to be some_type. Again, we substitute the parameter back into the partial specialization State<T, std::enable_if_t<std::is_arithmetic_v<T>>>. However, std::is_arithmetic_v<some_type> will now be false, which will lead to std::enable_if_t<…> not being defined and substitution fails. Since substituion failure is not an error in this context, this simply means that the partial specialization is not an option here and the primary template will be used instead.

If there were multiple matching partial specializations, they then would have to be ranked to pick the best match. The actual process is quite complicated, but it generally boils down to picking the most concrete specialization.

Partial class template specialisation for multiple types

I suppose you can use a boolean default value, like in foo struct in the following example

#include <iostream>

template <typename>
struct isSpecialType
{ static constexpr bool value { false }; };

template <>
struct isSpecialType<int>
{ static constexpr bool value { true }; };

template <>
struct isSpecialType<double>
{ static constexpr bool value { true }; };

template <typename T, bool = isSpecialType<T>::value>
struct foo;

template <typename T>
struct foo<T, true>
{ static constexpr bool value { true }; };

template <typename T>
struct foo<T, false>
{ static constexpr bool value { false }; };

int main()
{
std::cout << "- void value: " << foo<void>::value << std::endl;
std::cout << "- bool value: " << foo<bool>::value << std::endl;
std::cout << "- int value: " << foo<int>::value << std::endl;
std::cout << "- double value: " << foo<double>::value << std::endl;
}

The idea is define a sort of type traits (isSpecialType) to choose the selected types (int and double, in your example) with a booleand value that is false in the generic implementation and true in the specializations.

template <typename>
struct isSpecialType
{ static constexpr bool value { false }; };

template <>
struct isSpecialType<int>
{ static constexpr bool value { true }; };

template <>
struct isSpecialType<double>
{ static constexpr bool value { true }; };

Next you have to declare the foo struct (class Vec, in your question) with a supplemental bool template value with the isSpecialType<T>::value default value

template <typename T, bool = isSpecialType<T>::value>
struct foo;

Last, you have to implement two partially specialized version of foo: the first one with the boolean true value

template <typename T>
struct foo<T, true>
{ static constexpr bool value { true }; };

corresponding to the specialized version of your Vec; the one with the false boolean value

template <typename T>
struct foo<T, false>
{ static constexpr bool value { false }; };

corresponding to the generic version of your Vec.

Another point: my example is C++11 or newer code; if you want a C++98 version, you have only to define the bool values as const (instead constexpr) and initialize they whit the C++98 style; I mean

 static bool const bool value = true;

instead of

 static constexpr bool value { true };

C++ template function explicit specialization with multiple template types

template<bool B, typename T>
void foo(T const&)
{
static_assert(false, "not implemented");
}

template<bool B>
void foo(short)
{
printf("it's a short!\n");
}

However, this is not really specialisation, but overloading, which is completely appropriate. In fact, you could omit the general case.

Template method specialization for multiple types

Using Walter Brown's (C++1z) void_t.

#include <iostream>
#include <type_traits>

template <typename...>
using void_t = void;

template <typename T, typename = void>
struct has_bar
: std::false_type { };

template <typename T>
struct has_bar<T, void_t<decltype( std::declval<T&>().bar() ) > >
: std::true_type { };

class A {
public:
void foo() { };
};

class B {
public:
void bar() { };
};

class C {
public:
void bar() { };
};

template <typename T>
typename std::enable_if<!has_bar<T>::value, void>::type
fun(T t) {
std::cout << "fun" << std::endl;
}

template <typename T>
typename std::enable_if<has_bar<T>::value, void>::type
fun(T t) {
std::cout << "special fun" << std::endl;
}

The code...

int main(const int argc, const char* argv[argc]) {

A a;
B b;
C c;

fun(a);
fun(b);
fun(c);

return 0;
}

prints out

fun
special fun
special fun

Note, that does not check any type semantics, so it may be better declaring bar() as an interface and using std::is_base_of.

Template specialization for a class which has multiple types

Remove the second set of template parameters from your func1 definition and the template <>:

template <typename T>
unsigned int classx<int,T>::func1(int key)
{
return 1;
}

EDIT:

Additionally, you cannot partially specialize a single function of a template class. If you wish to do so, you will have to partially specialize the entire class.

Specialization of a template function with multiple template parameters in C++ 11

Partial specialization is not allowed for function templates, it could be used only for class templates.

You can apply function templates overloading with SFINAE. e.g.

// used when C is specified as char
template<typename C, typename T>
inline typename std::enable_if<std::is_same<C, char>::value, std::string>::type InternalToString(T val)
{
return std::to_string(val);
}

// used when C is specified as wchar_t
template<typename C, typename T>
inline typename std::enable_if<std::is_same<C, wchar_t>::value, std::wstring>::type InternalToString(T val)
{
return std::to_wstring(val);
}

// used when C is specified as other types
template<typename C, typename T>
typename std::enable_if<!std::is_same<C, char>::value && !std::is_same<C, wchar_t>::value, std::basic_string<C>>::type InternalToString(T val);


Related Topics



Leave a reply



Submit