我最近看到一些基于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
,其中我们有两个由逗号运算符分隔的表达式。如果无法评估第一个表达式,SFINAE会启动并拒绝过载。如果可以计算表达式,那么,由于逗号运算符,函数将返回void
。
据我了解,void()
&#34;构建&#34;未评估上下文中的void
对象(是的,这是合法的),然后由decltype
选择,因此void
是函数的返回类型。
我的问题是:为什么我们不能使用void{}
呢?它是否具有&#34;构建&#34;的相同效果?未评估的上下文中的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)
答案 0 :(得分:8)
这是一个表达。 [expr.type.conv] / P2-3:
表达式
T()
,其中T
是简单类型说明符或 typename-specifier 表示非数组完整对象类型或 (可能是cv-qualified)void
类型,创建一个prvalue 指定的类型,其值是由值初始化生成的 (8.5)T
类型的对象;没有进行初始化void()
案例。 [注意:... - 结束注释]同样,简单类型说明符或 typename-specifier 后跟一个 braced-init-list 创建指定类型的临时对象 使用指定的 braced-init-list direct-list-initialized (8.5.4), 它的值是临时对象作为prvalue。
您无法创建void
类型的临时对象。 void()
是一个特殊例外,可让您制作void
prvalue。