Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “void\u t”是如何工作的_C++_Templates_C++14_Sfinae - Fatal编程技术网

C++ “void\u t”是如何工作的

C++ “void\u t”是如何工作的,c++,templates,c++14,sfinae,C++,Templates,C++14,Sfinae,我观看了沃尔特·布朗在Cppcon14上关于现代模板编程(,)的演讲,他在演讲中介绍了他的void\tSFINAE技术 示例: 给定一个简单的变量模板,如果所有模板参数格式正确,则该模板的计算结果为void: template< class ... > using void_t = void; 模板使用void\u t=void; 以及检查名为member的成员变量是否存在的以下特征: template 结构具有\u成员:std::false\u类型 { }; //专门化为成员或

我观看了沃尔特·布朗在Cppcon14上关于现代模板编程(,)的演讲,他在演讲中介绍了他的
void\t
SFINAE技术

示例:
给定一个简单的变量模板,如果所有模板参数格式正确,则该模板的计算结果为
void

template< class ... > using void_t = void;
模板使用void\u t=void;
以及检查名为member的成员变量是否存在的以下特征:

template
结构具有\u成员:std::false\u类型
{ };
//专门化为成员或丢弃(sfinae)
模板
结构具有\u成员>:std::true\u类型
{ };
我试着去理解这是为什么,是如何运作的。因此,有一个小小的例子:

class A {
public:
    int member;
};

class B {
};

static_assert( has_member< A >::value , "A" );
static_assert( has_member< B >::value , "B" );
A类{
公众:
国际会员;
};
B类{
};
静态断言(has_成员::值,“A”);
静态断言(has_成员:值,“B”);
1.
有成员

  • has\u member>
    • A::成员
      存在
    • decltype(A::member)
      格式正确
    • void\t
      有效,计算结果为
      void
  • 具有_member
    ,因此它选择专门的模板
  • 具有\u成员
    并计算为
    true\u类型
2.
有成员

  • has\u member>
    • B::成员
      不存在
    • decltype(B::member)
      格式不正确,并以静默方式失败(sfinae)
    • 有\u成员
      ,因此此模板被丢弃
  • 编译器发现
    具有\u成员
    ,默认参数为void
  • has_成员
    的计算结果为
    false_类型

问题:
1.我对这一点的理解正确吗?
2.Walter Brown指出,默认参数必须与
void\t
中使用的参数类型完全相同,才能正常工作。为什么呢?(我不明白为什么这些类型需要匹配,不是只有任何默认类型才需要匹配吗?

//专门化为成员或丢弃(sfinae)
模板
结构具有\u成员:true\u类型
{ };
上述专门化只有在格式良好时才存在,因此当
decltype(T::member)
有效且不含糊时。 专门化是这样的,因为
在注释中有_member
作为状态

当您编写
has_member
时,由于默认模板参数,它是
has_member

我们对
has\u member
有专门化(因此继承自
true\u type
),但对
has\u member
没有专门化(因此我们使用默认定义:继承自
false\u type

1)。主类模板 编写
has_member::value
时,编译器将查找名称
has_member
,并找到主类模板,即此声明:

template< class , class = void >
struct has_member;
编译器尝试将模板参数
A,void
与部分专门化中定义的模式逐一匹配:
T
void\u T
首先执行模板参数推断。上面的部分专门化仍然是一个模板,其模板参数需要由参数“填充”

第一个模式允许编译器推断模板参数
T
。这是一个微不足道的演绎,但是考虑一种模式,如代码> T const和<代码>,在这里我们仍然可以推断出<代码> t>代码>。对于模式
T
和模板参数
A
,我们推断
T
A

在第二个模式中,模板参数
t
出现在无法从任何模板参数推断的上下文中

原因有两个:

  • decltype
    中的表达式被明确排除在模板参数推导之外。我想这是因为它可以任意复杂

  • 即使我们使用了一个没有
    decltype
    的模式,比如
    void\u t
    ,那么
    t
    的推断也会发生在解析的别名模板上。也就是说,我们解析别名模板,然后尝试从结果模式推断类型
    T
    。然而,结果模式是
    void
    ,它不依赖于
    T
    ,因此不允许我们为
    T
    找到特定类型。这类似于试图反转一个常数函数的数学问题(在这些术语的数学意义上)

模板参数推导已完成(*),现在已替换推导的模板参数。这将创建如下所示的专门化:

template<>
struct has_member< A, void_t< decltype( A::member ) > > : true_type
{ };
模板
结构具有\u成员>:true\u类型
{ };
现在可以计算类型
void\t
。它在替换后形成良好,因此,不会发生替换失败。我们得到:

template<>
struct has_member<A, void> : true_type
{ };
模板
结构具有\u成员:true\u类型
{ };
3.选择 现在,我们可以将此专门化的模板参数列表与提供给原始
has_member::value
的模板参数进行比较。这两种类型完全匹配,因此选择此部分专门化


另一方面,当我们将模板定义为:

template< class , class = int > // <-- int here instead of void
struct has_member : false_type
{ };

template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : true_type
{ };
模板//
结构具有\u成员>:true\u类型
{ };
我们最终得到了同样的专业化:

template<>
struct has_member<A, void> : true_type
{ };
模板
结构具有\u成员:true\u类型
{
template<>
struct has_member<A, void> : true_type
{ };
template< class , class = int > // <-- int here instead of void
struct has_member : false_type
{ };

template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : true_type
{ };
template<>
struct has_member<A, void> : true_type
{ };