【问题标题】:Why cannot we use brace initializer in an un-evaluated context?为什么我们不能在未评估的上下文中使用大括号初始化器?
【发布时间】:2015-02-24 05:06:58
【问题描述】:

我最近看到一些基于 SFINAE 的代码如下所示:

template <typename T>
auto test(T &myclass) -> decltype(myclass.f(), void()) 
{
    // do something here, don't return anything (void)
}

基本上,上面的函数使用 SFINAE 拒绝所有类型为 T 且没有 f() 作为成员函数的参数。 SFINAE 发生在decltype 中,其中我们有 2 个由逗号运算符分隔的表达式。如果无法计算第一个表达式,SFINAE 将启动并拒绝重载。如果可以计算表达式,那么由于逗号运算符的存在,函数会返回 void

据我了解,void() 在未评估的上下文中“构造”void 对象(是的,这是合法的),然后由decltype 选择,所以void 是返回函数的类型。

我的问题是:为什么我们不能使用 void{} 来代替? 在未评估的上下文中“构造”void 对象的效果不一样吗?我的编译器 (g++/clang++) 不接受 void{} 代码

error: compound literal of non-object type 'void'(g++4.9/g++5)

error: illegal initializer type 'void' (clang++ 3.5)

【问题讨论】:

  • 是函数声明吗?我认为不能在decltype 中使用函数声明,而只能使用函数名称,但我可能又被最令人烦恼的解析所困扰;) 3 分钟后:我实际上很确定它不是 MVP,因为decltype(int(int)) x; 被拒绝,但decltype(int()) x;有效,x的类型为int

标签: c++ c++11 sfinae decltype


【解决方案1】:

这是一种表达方式。 [expr.type.conv]/p2-3:

表达式T(),其中T 是一个简单类型说明符typename-specifier 用于非数组完整对象类型或 (可能是 cv 限定的)void 类型,创建 指定类型,其值是通过值初始化产生的 (8.5) T 类型的对象;没有进行初始化 void() 案例。 [:... - 结束注]

类似地,一个 simple-type-specifiertypename-specifier 后跟一个 braced-init-list 创建一个指定类型的临时对象 direct-list-initialized (8.5.4) 与指定的braced-init-list, 它的值是作为prvalue的临时对象。

您不能创建void 类型的临时对象。 void() 是一个特殊的例外,它允许您创建 void prvalue。

【讨论】:

  • 有趣...所以T() 是一个prvalue,而T{} 是(几乎)一个xvalue,如果我理解正确的话
  • @vsoftco “它的价值是作为prvalue的临时对象”。
猜你喜欢
  • 2012-07-29
  • 2018-03-06
  • 2021-12-31
  • 2016-02-25
  • 2011-10-05
  • 2012-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多