26

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?

Vincent
  • 57,703
  • 61
  • 205
  • 388

3 Answers3

25

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

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
6

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).

Community
  • 1
  • 1
filmor
  • 30,840
  • 6
  • 50
  • 48
  • 1
    *literal type* is defined in 3.9/10; `void` is *not* a literal type in C++11. In C++14 (N3797) however, `void` *is* included in the literal types. So the OP's code will be conforming to C++14. – Casey Dec 09 '13 at 19:06
  • 2
    @Casey Also I think 7.1.5 paragraph 6 allows for this in C++11 – Shafik Yaghmour Dec 09 '13 at 19:07
  • 1
    @ShafikYaghmour Ahh, I agree. Interesting: this code specializes to a non-`constexpr` but `const` member function in C++11, or a `constexpr` and non-`const` member function in C++14! – Casey Dec 09 '13 at 19:12
  • @Casey That would be correct if the declaration was for a non-`static` member function, but the OP has a `static` member so it won't be `const` in any case. Please pay attention, idiot! – Casey Dec 09 '13 at 19:15
1

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.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740