我不明白为什么这段代码编译没有错误:
#include <iostream>
template <class T>
struct Test
{
static constexpr T f() {return T();}
};
int main()
{
Test<void> test;
test.f(); // Why not an error?
return 0;
}
按照标准可以吗,还是编译器可以容忍?
根据C++11标准草案,这看起来是有效的,如果我们看一下第
5.2.3
节显式类型转换(函数符号)段落2说(强调我的):
表达式 T(),其中 T 是简单类型说明符或 非数组完整对象类型的类型名说明符 或 (可能是 cv 限定的)void 类型,创建 指定类型,其值是通过值初始化产生的 (8.5) T 类型的对象; void() 没有进行初始化 案例。[...]
措辞也非常相似 C++11 之前。
这在 constexpr 中没问题,尽管第
7.1.5
段落 3
说:
constexpr函数的定义应满足以下条件 限制条件:
并包括此项目符号:
其返回类型应为文字类型;
and void 不是 C++11 中的 literal,根据第
3.9
段落 10,但是,如果我们然后查看第 6 段落,它给出了适合这种情况的例外,它说:
如果 constexpr 函数的实例化模板特化 类模板的模板或成员函数将无法满足 constexpr 函数或 constexpr 构造函数的要求, 该专门化不是 constexpr 函数或 constexpr 构造函数。 [ 注意:如果该函数是成员函数,它将 仍然是 const ,如下所述。 —尾注] 如果没有专业化 模板将生成 constexpr 函数或 constexpr 构造函数,程序格式错误;无需诊断。
正如 Casey 在 C++14 草案标准中指出的那样,void是一个文字,这是第
3.9
类型段落10说:
如果满足以下条件,则类型是文字类型:
并包括:
——无效;或
有关完整信息,请参阅@Shafik Yaghmour 的答案。
以下段落禁止非模板这样做(7.1.5(3)):
函数的定义应满足以下约束:constexpr
[...]
其返回类型应为文字类型或对文字类型的引用
详细来说,3.9(10)中将文字类型定义为标量类型或数组或结构中文字类型对象的组合。根据 3.9(9),
void
不是标量类型。
您的函数返回
void()
的值,您本身并不是从 void 函数返回。您正在返回一个 NULL
值。你正在做的事情相当于这样:
void f() { return void(); }
这会返回一个空值,唯一的空值。您不能从 void 函数返回任何其他内容,因为它将是不同的类型。