为什么我们不能在未评估的上下文中使用大括号初始化程序?

Why cannot we use brace initializer in an un-evaluated context?

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

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

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

据我了解,void() "constructs" 未评估上下文中的 void 对象(是的,这是合法的),然后由 decltype 所以 void 是函数的 return 类型。

我的问题是:为什么我们不能用void{}来代替?它不是和"constructing"一个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)

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

The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type, whose value is that produced by value-initializing (8.5) an object of type T; no initialization is done for the void() case. [Note: ... - end note]

Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4) with the specified braced-init-list, and its value is that temporary object as a prvalue.

您不能创建 void 类型的临时对象。 void() 是一个特殊的例外,允许您制作 void 纯右值。