努力与类型列表的实现 [英] Struggling with implementation of a type list
问题描述
出于教育目的,我想编写我自己的 c ++ 11
基于类型列表。裸列表如下所示:
template< typename ... Ts> struct type_list;
template< typename T,typename ... Ts>
struct type_list< T,Ts ...> {
typedef T Head;
typedef type_list< Ts ...>尾巴;
};
template< typename T> struct type_list< T> {
typedef T Head;
typedef null_type Tail;
};
我创建了一个 front
提取第一个元素:
template< typename T&结构体
template< typename TypeList>
struct front {
typedef typename TypeList :: Head type;
};
它的工作原理如下:
< pre class =lang-c ++ prettyprint-override>
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;
产生:
front(lst1):i
front(lst2):f
front(lst3):d
front(lst4):c
自然地,返回
函数是下一步,但是,似乎得到它的工作。我的代码
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;
};
无法编译( clang 3.2
)[ lst
定义如前]:
TypeList.cc:33:71:error:在'null_type'中没有名为'Tail'的类型
typedef typename std :: conditional< std :: is_same< typename TypeList :: Tail,null_type> :: value,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ back< null_type>'请求这里
typename返回< typename TypeList :: Tail> :: type> :: type type;
^
TypeList.cc:54:44:note:
在实例化模板类'back< type_list< int> >'requested here
std :: cout<< back(lst1):< typeid(back< lst> :: type).name()<< std :: endl;
^
生成了1个错误。
问题
- 为什么
std :: conditional
不会触发?
std :: conditional
的不当使用 std :: conditionalonal< condition,true-type,false-type>
您的问题归结为 true - 无论条件选择哪一侧, std :: conditional
都必须产生有效的名称。
注意:如果不需要完整说明,在此帖子末尾有一个建议的解决方案。
请考虑以下示例:
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;
};
实例化 some_trait< A> ;
将完全有效,但如果我们用 B
?实例化它会发生什么?
模板<>
struct some_trait< B> {
typedef typename std :: conditional<
std :: is_same< B,A> :: value,
typename B :: type,//(A),ill-formed
void
>结果;
};
在上面我们假装是一个编译器,我们替换每一次出现的 T
与 B
,这不是所有的努力工作,但它提出了一个非常重要的问题,我们的主模板<当编译器使用 T = B
some_trait< T>
/ code>,我们的 std :: conditional
中的 true类型将是 B :: type
。 但由于 B
名称里面调用类型
,我们将得到一个编译器诊断说我们的代码有问题,即;我们正在尝试访问不存在的名称。
foo.cpp:15: 37:错误:在'B'中没有名为'type'的类型
/ * true-type - > * / typename T :: type,//(A),ill-formed
建议解决方案
毫无疑问,我们必须做什么,简而言之;防止我们的模板访问可能不存在的名称。
这样做的一个简单方法是依靠显式专门化 使用 std :: conditional
。
回执的示例实现
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;
};
注意:如果实例化 template< typename T> struct back;
是只有一个参数的 type_list
,我们知道我们在最后一个节点。
For educational purposes I want to write my own c++11
based typelist. The bare list looks like this:
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 have created a function called front
for extracting the first element:
template <typename T> struct front;
template <typename TypeList>
struct front {
typedef typename TypeList::Head type;
};
Which 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;
produces:
front(lst1): i
front(lst2): f
front(lst3): d
front(lst4): c
Naturally, a back
function is the next step, however, I can't seem to 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;
};
does not compile (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 the
std::conditional
not trigger?
Improper usage of std::conditional
std::conditonal<condition, true-type, false-type>
Your problem boils down to that both the true- and false-type in std::conditional
must yield a valid name, no matter which side the condition picks.
Note: There's a proposed solution at the end of this post if a full explanation isn't needed.
Consider the below 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;
};
Instantiating some_trait<A>
will be perfectly valid, but what happens if we instantiate 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 we are pretending to be a compiler, and we replaced every occurance of T
with B
, it's not all that hard work but it has raised a very important issue with our primary-template.
When the compiler instantiates some_trait<T>
with T = B
, the true-type in our std::conditional
will be B::type
(A).
But since B
has no name inside it called type
we will get a compiler diagnostic saying that there's something wrong with our code, namely; we are trying to access a name which doesn't exist.
foo.cpp:15:37: error: no type named 'type' in 'B'
/* true-type -> */ typename T::type, // (A), ill-formed
Proposed Solution
There really is no doubt to what we have to do, and to put it in short; prevent our template from accessing names that potentially doesn't exist.
A simple way of doing this is to rely on explicit specialization, instead of using a std::conditional
.
Sample implementation of back
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 the instantiation of template<typename T> struct back;
is a type_list
with only one parameter, we know we are at the last node.
这篇关于努力与类型列表的实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!