How to Decide If a Template Specialization Exist

How to decide if a template specialization exist

Using the fact that you can't apply sizeof to an incomplete type:

template <class T, std::size_t = sizeof(T)>
std::true_type is_complete_impl(T *);

std::false_type is_complete_impl(...);

template <class T>
using is_complete = decltype(is_complete_impl(std::declval<T*>()));

See it live on Coliru


Here is a slightly clunky, but working C++03 solution:

template <class T>
char is_complete_impl(char (*)[sizeof(T)]);

template <class>
char (&is_complete_impl(...))[2];

template <class T>
struct is_complete {
enum { value = sizeof(is_complete_impl<T>(0)) == sizeof(char) };
};

See it live on Coliru

How to test if exists a template function specialization

You could do it by placing a static_assert in the primary function template with a little trick that will assure that your program is not ill formed, stolen shamelessly from here :

template <typename...> struct always_false : std::false_type {};

template<typename T, typename U> double convert(double) {
static_assert(always_false<T, U>::value, "No specialization exists!");
}

template <> double convert<Kilometer, Mile>(double val) { return val/1609.344; }
template <> double convert<Mile, Kilometer>(double val) { return 1609.344*val; }

Live Demo

Check if a template has a specialization for a given type

@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
^

Check if class is a template specialization?

Here's one where you can provide the template to be matched against :

template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};

template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};

static_assert(is_specialization<std::vector<int>, std::vector>{}, "");
static_assert(!is_specialization<std::vector<int>, std::list>{}, "");

Check if valid template specialization

The following is easier and works:

template<template<typename...> class C, typename... T>
struct is_valid_specialization {
typedef struct { char _; } yes;
typedef struct { yes _[2]; } no;

template<template<typename...> class D>
static yes test(D<T...>*);
template<template<typename...> class D>
static no test(...);

constexpr static bool value = (sizeof(test<C>(0)) == sizeof(yes));
};

Live example

C++ concept to check for derived from template specialization

De-_Ugly-fied rom MSVCSTL:

template <template <class...> class Template, class... Args>
void derived_from_specialization_impl(const Template<Args...>&);

template <class T, template <class...> class Template>
concept derived_from_specialization_of = requires(const T& t) {
derived_from_specialization_impl<Template>(t);
};

which we use to implement the exposition-only type trait is-derived-from-view-interface from [range.view]/6.

Note that this has the same limitation as the is_specialization_of trait cited in the OP: it works only with templates that have all type parameters.

[DEMO]

How to know if a type is a specialization of std::vector?

In C++11 you can also do it in a more generic way:

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

template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};

template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};

int main()
{
typedef std::vector<int> vec;
typedef int not_vec;
std::cout << is_specialization<vec, std::vector>::value << is_specialization<not_vec, std::vector>::value;

typedef std::list<int> lst;
typedef int not_lst;
std::cout << is_specialization<lst, std::list>::value << is_specialization<not_lst, std::list>::value;
}


Related Topics



Leave a reply



Submit