2013-12-09 12 views
25

Nie rozumiem dlaczego ten kod kompiluje bez błędów:Zwrot pustki?

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

Czy to jest ok, zgodnie z normą, czy jest to tolerancja kompilator?

+0

Cóż, wiem, że może mieć, powiedzmy, 'void foo() {} void bar() {return foo();}'. Nie jestem pewien co do tego. – chris

+1

O co konkretnie chodzi? O zwrocie 'void' (który, BTW, zawsze był legalny w C++)? Lub o kombinacji 'constexpr void'? – AnT

+3

Może powinieneś wyjaśnić, co Twoim zdaniem powinien być błąd? –

Odpowiedz

24

Wygląda to ważny przez draft C++11 standard, jeśli spojrzymy na odcinku 5.2.3Jawna konwersja typu (notacja funkcjonalna) ustęp mówi (podkr):

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.[...]

sformułowanie jest dość podobna pre C++11 również.

to w porządku w constexpr choć sekcja 7.1.5 ustęp 3 mówi:

The definition of a constexpr function shall satisfy the following constraints:

i obejmuje tę kulę:

its return type shall be a literal type;

i void nie jest dosłowne w C++ 11 zgodnie z sekcją 3.9 ustęp , ale gdybyśmy potem spojrzeć w pkt daje wyjątek, który pasuje do tej sprawy, to mówi:

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.

Jak Casey noted w C++14 draft standardvoid jest dosłowny, to sekcja 3.9Rodzaje pkt mówi:

A type is a literal type if it is:

i obejmuje:

— void; or

6

Zobacz odpowiedź @Shafik Yaghmour dla pełnej informacji.

dodaje się ust zabrania to tylko dla wzorów (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

celu opracowania, typ jest określony w dosłownym 3,9 (10) w postaci skalarnej typu lub składu obiekty typu literalnego w tablicy lub strukturze. void nie jest typem skalarnym o 3,9 (9).

+1

* typ literalny * jest zdefiniowany w 3.9/10; 'void' to * nie * typ literalny w C++ 11. W C++ 14 (N3797) jednak "void' * jest * zawarty w typach literalnych. Kod OP będzie więc zgodny z C++ 14. – Casey

+2

@Casey Również myślę, że 7.1.5 pkt 6 pozwala na to w C++ 11 –

+1

@ShafikYaghmour Ahh, zgadzam się. Interesujące: ten kod specjalizuje się w funkcji użytkownika non-'constexpr', ale 'const' w C++ 11 lub funkcji składowej' constexpr' i non -'const' w C++ 14! – Casey

1

Twoja funkcja zwraca wartość void(), nie powracasz z funkcji nieważności jako takiej. Zwracasz wartość NULL. To, co robisz, jest równoważne z tym:

void f() { return void(); } 

Zwraca pustą wartość, jedyną pustą wartość. nie możesz zwrócić niczego innego z funkcji void, ponieważ będzie ona innego rodzaju.

+0

Jestem prawie pewien, że jest to dozwolone w C++ przez 5.2.3 (2), choć IANALL. – filmor

+0

Jest to dozwolone przez kompilator, ale nie jest tak naprawdę użyteczne, ponieważ nie ma żadnej wartości. – user3084096

+2

Nie o to chodzi podczas rozmowy o standardach językowych. – filmor