Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ partial template specialization in combination with std::is_base_of and std::enable_if

Let's say I have a two classes: Serializable and Printable.

So a simple template function which accepts all derived classes of Printable could look like:

template <class T, class B = Printable, class = typename std::enable_if<std::is_base_of<B,     T>::value>::type> void print(T value) {     cout << value << endl; } 

However, if I want it to accept also all derived classes of Serializable while I still have control over the function body, this would obviously not work:

template <class T, class B = Printable, class = typename std::enable_if<std::is_base_of<B,     T>::value>::type> void print(T value) {     cout << value << endl; }  template <class T, class B = Serializable, class = typename std::enable_if<std::is_base_of<B,     T>::value>::type> void print(T value) {     cout << value << endl; }  // Error: Redefinition of ... 

So I figured the remaining solutions for this problem are template specializations.

But I just can't figure out, how I can specialize a template in combination with std::is_base_of and std::enable_if.

I hope someone is willing to help me!

like image 992
Tim Avatar asked Jun 19 '13 20:06

Tim


People also ask

What is the purpose of std :: Enable_if?

In C++ metaprogramming, std::enable_if is an important function to enable certain types for template specialization via some predicates known at the compile time. Using types that are not enabled by std::enable_if for template specialization will result in compile-time error.

What is meant by template specialization in C++?

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.


1 Answers

Try a logical operator:

std::enable_if<std::is_base_of<Serializable, T>::value ||                std::is_base_of<Printable, T>::value>::type 

You can easily write a variadic template like:

is_base_of_any<T, Printable, Serialiable, Googlable, Foobarable>::value 

For example:

template <typename T, typename ...> struct is_base_of_any : std::true_type {};  template <typename T, typename Head, typename ...Rest> struct is_base_of_any<T, Head, Rest...> : std::integral_constant<bool, std::is_base_of<T, Head>::value ||                                is_base_of_any<T, Rest...>::value> { }; 

If you want different implementations:

template <bool...> struct tag_type {};  template <typename T> void foo(T, tag_type<true, false>) { }   // for Printable  template <typename T> void foo(T, tag_type<false, true>) { }   // for Serializable  template <typename T> void foo(T x) {     foo(x, tag_type<std::is_base_of<Printable, T>::value,                     std::is_base_of<Serializable, T>::value>()); } 

The last overload (the "user-facing" one) should probably be endowed with the above enable_if to not create overly many overload candidates.

You can probably also make a variadic template <typename ...Bases> with a tag like:

tag_type<std::is_base_of<Bases, T>::value...> 
like image 86
Kerrek SB Avatar answered Sep 18 '22 13:09

Kerrek SB