Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ templates that accept only certain types

Tags:

c++

templates

In Java you can define generic class that accept only types that extends class of your choice, eg:

public class ObservableList<T extends List> {   ... } 

This is done using "extends" keyword.

Is there some simple equivalent to this keyword in C++?

like image 903
mgamer Avatar asked May 17 '09 10:05

mgamer


People also ask

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.

What is the difference between template typename T and template T?

There is no difference. typename and class are interchangeable in the declaration of a type template parameter.

Can templates be used for user defined data types?

Template in C++is a feature. We write code once and use it for any data type including user defined data types. For example, sort() can be written and used to sort any data type items. A class stack can be created that can be used as a stack of any data type.

What is the main problem with templates C++?

C++ templates can't use normal run-time C++ code in the process of expanding, and suffer for it: for instance, the C++ factorial program is limited in that it produces 32-bit integers rather than arbitrary-length bignums.


1 Answers

This typically is unwarranted in C++, as other answers here have noted. In C++ we tend to define generic types based on other constraints other than "inherits from this class". If you really wanted to do that, it's quite easy to do in C++11 and <type_traits>:

#include <type_traits>  template<typename T> class observable_list {     static_assert(std::is_base_of<list, T>::value, "T must inherit from list");     // code here.. }; 

This breaks a lot of the concepts that people expect in C++ though. It's better to use tricks like defining your own traits. For example, maybe observable_list wants to accept any type of container that has the typedefs const_iterator and a begin and end member function that returns const_iterator. If you restrict this to classes that inherit from list then a user who has their own type that doesn't inherit from list but provides these member functions and typedefs would be unable to use your observable_list.

There are two solutions to this issue, one of them is to not constrain anything and rely on duck typing. A big con to this solution is that it involves a massive amount of errors that can be hard for users to grok. Another solution is to define traits to constrain the type provided to meet the interface requirements. The big con for this solution is that involves extra writing which can be seen as annoying. However, the positive side is that you will be able to write your own error messages a la static_assert.

For completeness, the solution to the example above is given:

#include <type_traits>  template<typename...> struct void_ {     using type = void; };  template<typename... Args> using Void = typename void_<Args...>::type;  template<typename T, typename = void> struct has_const_iterator : std::false_type {};  template<typename T> struct has_const_iterator<T, Void<typename T::const_iterator>> : std::true_type {};  struct has_begin_end_impl {     template<typename T, typename Begin = decltype(std::declval<const T&>().begin()),                          typename End   = decltype(std::declval<const T&>().end())>     static std::true_type test(int);     template<typename...>     static std::false_type test(...); };  template<typename T> struct has_begin_end : decltype(has_begin_end_impl::test<T>(0)) {};  template<typename T> class observable_list {     static_assert(has_const_iterator<T>::value, "Must have a const_iterator typedef");     static_assert(has_begin_end<T>::value, "Must have begin and end member functions");     // code here... }; 

There are a lot of concepts shown in the example above that showcase C++11's features. Some search terms for the curious are variadic templates, SFINAE, expression SFINAE, and type traits.

like image 194
Rapptz Avatar answered Oct 06 '22 18:10

Rapptz