2017-02-02 19 views
8
int x = 1; // Not Constant 

class A { 
    public: 
     int value = x; 
     int value2 { x }; 
     A(int a)  : value(x), value2(x) {} 
     A(int a, int b) : value{ x }, value2{ x } {} 
     constexpr A() : value{ 0 }, value2{ 0 } {} 
}; 

constexpr int function(A obj1, A obj2, A obj3, A obj4, A obj5, A obj6, A obj7){ 
    return 1; 
} 

int main(){ 

    int y = 2; // Not Constant 
    A obj1 (y); 
    A obj2 { y }; 
    A obj3 = y ; 
    A obj4 = { y }; 
    A obj5 (y, y); 
    A obj6 { y, y); 
    A obj7 = { y, y }; 
    int var = function(obj1, obj2, obj3, obj4, obj5, obj6, obj7); 

    return 0; 
} 

C++ 11 Standard (ISO/IEC 14882: 2011), sekcja 3.9, pkt 10 stanów (Kopalnia nacisk):Dosłowne Rodzaj Klasy w C++ 11/C++ 14

Typ jest dosłowny rodzaj jeśli jest to:

  • typu skalarnego; lub
  • typ odniesienia; lub
  • typu klasy (Rozdział 9), który posiada wszystkie z następujących właściwości:
    • ma trywialne destructor
    • każde połączenie konstruktora pełnej ekspresji w szynie albo-same wymiary initializers dla nie statycznych elementów danych (jeśli występują) jest wyrażeniem stałym (5.19),
    • jest to typ agregacyjny (8.5.1) lub ma co najmniej jeden konstruktor constexpr lub szablon konstruktora, który nie jest kopią lub przenieść konstruktora i
    • go ma wszystkie niestatyczne elementy danych i klasy bazowe typów literowych; lub
  • tablica typu literalnego.

Moim zdaniem, biorąc pod uwagę kulę w pogrubienie, class A nie jest dosłownym typu w C++ 11, ponieważ nie ma połączenia konstruktor i klamra lub równy-inicjalizatory danych non-statycznej członkowie, którzy nie są wyrażeniami stałymi. Próbowałem wstawić constexpr przed definicją konstruktora, a także przypisać wywołanie konstruktora do zmiennej constexpr, aby sprawdzić, czy rzeczywiście kompilator narzeka, ponieważ nie są to wyrażenia stałe. Jednak zarówno Clang, jak i GCC skompilują go pomyślnie. Więc prawdopodobnie jestem w błędzie.

  • Czy ktoś wie, dlaczego class A jest literałem?

Pocisk pogrubione usunięto C++ 14 (N3652), więc rozumie class A jest dosłownym typu C++ 14. Muszę wiedzieć, ponieważ function jest constexpr, a zatem each of its parameter types shall be a literal type (C++ 11/C++ 14 Standard, Rozdział 7.1.15, Ustęp 3).

EDYCJA: W oryginalnym poście użyłem prostego przykładu, aby ułatwić czytanie i wyjaśniłem, że próbowałem już wielu kombinacji. Teraz zaktualizowałem ten przykład niektórymi z tych kombinacji, aby pokazać, że próbowałem różnych wywołań konstruktora, definicji i niestatycznych inicjalizacji elementów danych. Dzięki.

+0

"Czy ktoś wie, dlaczego klasa A jest literalna? *" Nie jest to w C++ 11. I żaden z kodu, który pokazałeś * nie wymaga * żeby był literalnym typem. Więc w czym problem? –

+0

Czy wiesz, czym jest * inicjator klamrowy lub równy *? –

+0

@ T.C. Myślę, że * inicjator typu "brace-lub-equal" to 'int x {y}' lub 'int x = y'. Zwykle mówię * member-initializer-list * dla inicjalizacji w konstruktorze, jak podczas inicjalizacji 'value' w' A (int z): value (x) {} ', ale przeczytałem też wiele osób odnoszących się do tego jak * inicjator typu "brace-lub-equal" *. Proszę mnie poprawić, jeśli popełniłem jakiś błąd. W każdym przypadku próbowałem wielu kombinacji nawiasów klamrowych, równych itd. Zarówno dla samego obiektu, jak i dla zmiennej 'value' w konstruktorze, a wynik jest taki sam. Dzięki. –

Odpowiedz

3

Czy ktoś wie, dlaczego klasa A jest literalna?

Nie ma go w C++ 11, ale jest w C++ 14, z powodów, które cytujesz w swoim poście. Jednak ...

Jednak zarówno Clang, jak i GCC skompilowały go pomyślnie. Więc prawdopodobnie jestem w błędzie.

Nie mylisz się. Ani clang ani gcc. Kod jest rzeczywiście dobrze uformowany pomimo tego, że A nie jest typem dosłownym ... po prostu dlatego, że nic nie wymaga tego, aby był literalnym typem. function może być funkcją constexpr, ale nie jest wywoływana jako wyrażenie stałe. var nie jest obiektem constexpr, więc nie ma wymuszonego wymogu, aby wszystkie obiekty były typu literalnego. Gdybyś spróbował:

constexpr int var = function(...); 

następnie kod będzie źle sformułowane, tak jak w tym przypadku, function(...) musiałyby być rdzeń stałym wyrażeniem, które wymaga dosłownych rodzajów, co jest wymogiem, że w C + +11 A nie powiodło się. (Właściwie, masz również problem z C++ 14, że żaden z obiektów A nie jest obiektem constexpr).