Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decide if a template specialization exist

I would like to check if a certain template specialization exist or not, where the general case is not defined.

Given:

template <typename T> struct A; // general definition not defined
template <> struct A<int> {};   // specialization defined for int

I would like to define a struct like this:

template <typename T>
struct IsDefined
{
    static const bool value = ???; // true if A<T> exist, false if it does not
};

Is there a way to do that (ideally without C++11)?

Thanks

like image 484
Fabio Avatar asked May 28 '17 16:05

Fabio


People also ask

What is template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

Why does the need of template specialization arise?

It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.

Are template specializations inline?

An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.


2 Answers

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

like image 110
Quentin Avatar answered Sep 19 '22 15:09

Quentin


This is an alternative implementation always using the same trick @Quentin used


C++11 version

template<class First, std::size_t>
using first_t = First;

template<class T>
struct is_complete_type: std::false_type {};

template<class T>
struct is_complete_type<first_t<T, sizeof(T)>> : std::true_type {};

Example on wandbox


Tentative C++03 version which does not work

template<typename First, std::size_t>
struct first { typedef First type; };

template<typename T>
struct is_complete_type { static const bool value = false; };

template<typename T>
struct is_complete_type< typename first<T, sizeof(T)>::type > { static const bool value = true; };

The error in this case is

prog.cc:11:8: error: template parameters not deducible in partial specialization: struct is_complete_type< typename first::type > { static const bool value = true; }; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

prog.cc:11:8: note: 'T'

like image 41
Makers_F Avatar answered Sep 17 '22 15:09

Makers_F