问题
I do not understand why this code compiles without error:
#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;
}
Is it ok according to the standard, or is it a compiler tolerance?
回答1:
This looks valid by the draft C++11 standard, if we look at section 5.2.3
Explicit type conversion (functional notation) paragraph 2 says (emphasis mine):
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.[...]
the wording is pretty similar pre C++11 as well.
This okay in a constexpr even though section 7.1.5
paragraph 3
says:
The definition of a constexpr function shall satisfy the following constraints:
and includes this bullet:
its return type shall be a literal type;
and void is not a literal in C++11 as per section 3.9
paragraph 10, but if we then look at paragraph 6 it gives an exception that fits this case, it says:
If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is not a constexpr function or constexpr constructor. [ Note: If the function is a member function it will still be const as described below. —end note ] If no specialization of the template would yield a constexpr function or constexpr constructor, the program is ill-formed; no diagnostic required.
As Casey noted in the C++14 draft standard void is a literal, this is section 3.9
Types paragraph 10 says:
A type is a literal type if it is:
and includes:
— void; or
回答2:
See @Shafik Yaghmour's answer for the full info.
The following paragraph forbids this for non-templates (7.1.5(3)):
The definition of a
constexpr
function shall satisfy the following constraints:
[...]
its return type shall be a literal type or a reference to literal type
To elaborate, a literal type is defined in 3.9(10) as a scalar type or a composition of literal type objects in an array or struct. void
is not a scalar type by 3.9(9).
回答3:
Your function returns the value of void()
, you are not returning from a void function per se. You are returning a NULL
value. What you are doing is equivalent to this:
void f() { return void(); }
This returns a void value, the only void value. you can't return anything else from a void function because it will be of a different type.
来源:https://stackoverflow.com/questions/20478193/returning-a-void