Fighting Type List Implementation

For educational purposes, I want to write my own c++11 type directory. The bare list is as follows:

 template <typename ... Ts> struct type_list; template <typename T, typename ... Ts> struct type_list<T, Ts ...> { typedef T Head; typedef type_list<Ts ...> Tail; }; template <typename T> struct type_list<T> { typedef T Head; typedef null_type Tail; }; 

I created a function called front to retrieve the first element:

 template <typename T> struct front; template <typename TypeList> struct front { typedef typename TypeList::Head type; }; 

What works as expected, i.e. this code

 typedef type_list<int> lst; typedef type_list<float,int> lst2; typedef type_list<double,float,int> lst3; typedef type_list<char,double,float,int> lst4; std::cout << "front(lst1): " << typeid( front<lst>::type ).name() << std::endl; std::cout << "front(lst2): " << typeid( front<lst2>::type ).name() << std::endl; std::cout << "front(lst3): " << typeid( front<lst3>::type ).name() << std::endl; std::cout << "front(lst4): " << typeid( front<lst4>::type ).name() << std::endl; 

gives:

front (lst1): i
front (lst2): f front (lst3): d
front (lst4): c

Naturally, the back function is the next step, however I cannot get it to work. My code

 template <typename T> struct back; template <typename TypeList> struct back { typedef typename std::conditional<std::is_same<typename TypeList::Tail, null_type>::value, typename TypeList::Head, typename back<typename TypeList::Tail>::type>::type type; }; 

not compiled ( clang 3.2 ) [ lst is defined as before]:

 TypeList.cc:33:71: error: no type named 'Tail' in 'null_type' typedef typename std::conditional<std::is_same<typename TypeList::Tail, null_type>::value, ~~~~~~~~~~~~~~~~~~~^~~~ TypeList.cc:35:20: note: in instantiation of template class 'back<null_type>' requested here typename back<typename TypeList::Tail>::type>::type type; ^ TypeList.cc:54:44: note: in instantiation of template class 'back<type_list<int> >' requested here std::cout << "back(lst1): " << typeid( back<lst>::type ).name() << std::endl; ^ 1 error generated. 

Question

  • Why does std::conditional not start?
+6
source share
2 answers

Incorrect use of std::conditional

 std::conditonal<condition, true-type, false-type> 

Your problem boils down to the fact that both true and false types in std::conditional should give a valid name, regardless of which side chooses the condition.

Note It proposes a proposed solution at the end of this post if a full explanation is not required.


Consider the following example:

 struct A { typedef int type; }; struct B { /* empty */ }; 

 template<class T> struct some_trait { typedef typename std::conditional< /* condition -> */ std::is_same<T, A>::value, /* true-type -> */ typename T::type, /* false-type -> */ void >::type result; }; 

Running some_trait<A> will be absolutely correct, but what happens if we create it with B ?

 template<> struct some_trait<B> { typedef typename std::conditional< std::is_same<B, A>::value, typename B::type, // (A), ill-formed void >::type result; }; 

In the above example, we claim to be a compiler, and we replaced every T event with B , this is not all that works hard, but it raised a very important problem with our main template.

When the compiler instantiates some_trait<T> using T = B , the true-type in our std::conditional will be B::type (A).

But since B does not have a name inside it called type , we get a compiler diagnostics saying that something is wrong with our code, namely; we are trying to access a name that does not exist.

 foo.cpp:15:37: error: no type named 'type' in 'B' /* true-type -> */ typename T::type, // (A), ill-formed 


Proposed solution

In fact, there is no doubt what we should do, and briefly; do not let our template access names that do not potentially exist.

An easy way to do this is to use explicit specialization instead of using std::conditional .


back implementation example

 template<typename TypeList> struct back { typedef typename back<typename TypeList::Tail>::type type; }; template<typename T> struct back<type_list<T>> { typedef typename type_list<T>::Head type; }; 

Note If an instance of template<typename T> struct back; is type_list with only one parameter, we know that we are on the last node.

+7
source

The error occurs because the compiler tries to get the type name for the else part of the conditional expression, even if the conditional value is true.

You can fix this problem by creating a specialization back .

 template <typename T> struct back<type_list<T>> { typedef T type; }; 

Of course, then you can simplify another implementation

 template <typename TypeList> struct back { typedef typename back<typename TypeList::Tail>::type type; }; 
+4
source

Source: https://habr.com/ru/post/970465/


All Articles