Manu343726
Manu343726

Reputation: 14174

Check if a template has a specialization for a given type

Suppose we have a metafunction like this:

template<typename LHS , typename RHS>
struct add;

And we have a set of specializations for known types. For example, integral wrappers:

template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2>
struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2> : public std::integral_constant<std::common_type_t<T1,T2>,VALUE1+VALUE2> {}; //Take advantage of C++14 helpers

A few days ago, we create a new class, and we specialize addition for this class:

template<typename X , typename Y>
struct point_2d
{
    using x = X;
    using y = Y;
};

template<typename X1 , typename Y1 , typename X2 , typename Y2>
struct add<point_2d<X1,Y1>,ppoint_2d<X2,Y2>> : public point_2d<add<X1,X2>,add<Y1,Y2>> {};

As you can see, I used add metafuntion to perform the addition of the coordinates. So any type that has a specialization for add metafunction can be used as point_2d coordinates.

My question is: Is there any way to check if a template has a specialization with a given type as argument?

Something like this:

template<template<typename...> class TEMPLATE , typename... Ts>
struct has_specialization;

template<template<typename...> class TEMPLATE , typename... Ts>
struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> exists */ , Ts...> : public std::true_type {};

template<template<typename...> class TEMPLATE , typename... Ts>
struct has_specialization<TEMPLATE<Ts...> /* TEMPLATE<Ts...> doesn't exists */ , Ts...> : public std::false_type {};

Upvotes: 3

Views: 1865

Answers (1)

Mike Kinghan
Mike Kinghan

Reputation: 61192

@BartekBanachewicz the idea is to provide user friendly compiler errors through asserts. If i can check (Following with the point_2d example) if the coordinates passed are addable (That is, a specialization of add metafuncion is or not defined for that coordinates), I can provide more readable errors like "That coordinates are not addable. point_2d needs addable coordinates for point addition", instead of the common horrible template instantation errors.

Given that this is the motivation of your question would not this be an easier and more direct solution:

#include <type_traits>

template<typename LHS , typename RHS>
using cannot_add =  std::integral_constant<bool,std::is_same<LHS,LHS>::value>;

template<typename LHS , typename RHS>
struct add
{
    /* Assert some expressively named condition that is always false 
        but is dependent on a template parameter.
    */
    static_assert(!cannot_add<LHS,RHS>::value,
        "Types are not addable. Need specialization");
};

template<typename T1 , T1 VALUE1 , typename T2 , T2 VALUE2>
struct add<std::integral_constant<T1,VALUE1>,std::integral_constant<T2,VALUE2>> 
: public std::integral_constant<
    typename std::common_type<T1,T2>::type,
    VALUE1+VALUE2
> {};  

int main()
{
    add<std::integral_constant<int,1>,std::integral_constant<int,2>> x; // Line 25 
    add<float,float> y; // Line 26
    return 0;
}

GCC 4.8.1 diagnoses:

main.cpp:26:19:   required from here
main.cpp:12:2: error: static assertion failed: Types are not addable. Need specialization

Clang 3.3 diagnoses:

main.cpp:12:2: error: static_assert failed "Types are not addable. Need specialization"
    static_assert(!cannot_add<LHS,RHS>::value,
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:26:19: note: in instantiation of template class 'add<float, float>' requested here
    add<float,float> y; // Line 26
                 ^

Upvotes: 7

Related Questions