返回一个void类型?

26

我不明白为什么这段代码可以编译通过而没有错误:

#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;
}

这符合标准要求吗,还是编译器的容错机制?


嗯,我知道你可以这样写:void foo() {} void bar() {return foo();}。但我不确定。 - chris
1
你的问题具体是关于什么?是关于返回 void(顺便说一下,在 C++ 中一直是合法的)吗?还是关于 constexpr void 的组合? - AnT stands with Russia
3
也许你应该解释一下你认为错误是什么? - Lightness Races in Orbit
3个回答

25
根据C++11标准草案第5.2.3节“显式类型转换(函数表示法)”的第2段所述(重点在于强调),表达式T(),其中T是非数组完整对象类型的简单类型说明符或类型名说明符或(可能带有cv修饰符的)void类型,创建指定类型的prvalue,其值是通过使用类型T的对象进行值初始化(8.5)产生的;对于void()情况不进行初始化。该措辞在C++11之前也是相似的。
即使第7.1.5节第3段规定如下,这在constexpr中也是可以的:

constexpr函数的定义应满足以下约束条件:

并包括此项目符号:

其返回类型必须是字面类型;

而在C++11中,void不是字面量,如第3.9节第10段所述,但是如果我们再看第6段,它给出了适合此情况的例外,它说:

如果类模板的constexpr函数模板或成员函数的实例化模板专业化不符合constexpr函数或constexpr构造函数的要求,则该专业化不是constexpr函数或constexpr构造函数。[注:如果函数是成员函数,则仍将其作为下面所述的const。-结束说明] 如果没有模板的任何专业化会产生constexpr函数或constexpr构造函数,则程序无效;不需要诊断

正如Casey在这里指出的那样,在C++14标准草案中,void是一个字面量,这是第3.9节类型的第10段所说的:

如果它是:

并包括以下内容:
— 无返回值;或

6
请参阅 @Shafik Yaghmour 的答案以获取完整信息。
下面的段落禁止非模板使用 constexpr(7.1.5(3)):
“constexpr”函数的定义必须满足以下约束条件:
  • [...]
  • 其返回类型必须是文字类型或者文字类型的引用。
更进一步地,文字类型在 3.9(10) 中被定义为标量类型或者数组、结构体中文字类型对象的组合。根据 3.9(9),void 不是标量类型。

1
literal type 在3.9/10中被定义;在C++11中,void 不是 字面类型。然而,在C++14(N3797)中,void 被包括在 字面类型中。因此,OP的代码将符合C++14标准。 - Casey
2
@Casey 我认为7.1.5第6段允许在C++11中这样做。 - Shafik Yaghmour
1
@ShafikYaghmour 啊,我同意。有趣的是:这段代码在C++11中专门用于非constexprconst成员函数,或者在C++14中用于constexpr和非const成员函数! - Casey
@Casey 如果声明是非static成员函数,那么你说的是正确的,但是OP有一个static成员,所以无论如何它都不会是const。请注意,白痴! - Casey

1
你的函数返回void()的值,你并不是从一个void函数中返回。你返回了一个NULL值。你所做的相当于这样:
void f() { return void(); }

这返回一个空值,唯一的空值。你不能从一个空函数中返回其他任何东西,因为它将是不同类型的。

我相信这在C++中是被允许的,根据5.2.3(2),但我不是所有人。 - filmor
编译器允许这样做,但实际上它没有任何价值,也没有什么用处。 - user3084096
2
谈论语言标准时,这不是重点。 - filmor
@user3084096 在模板中作为参数化类型可能很有用,返回默认构造的元素。这可能会避免特殊情况。 - Tim Seguine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接