2017-12-31 152 views
14

Dlaczego cppreference definiuje skróty type_traits xxx_v jako inline constexpr, a nie tylko constexpr?Dlaczego cppreference definiuje skróty type_traits xxx_v jako inline constexpr, a nie tylko constexpr?

Na przykład, patrz is_integral_v:

template< class T > 
inline constexpr bool is_integral_v = is_integral<T>::value; 

Czy to tylko kwestia stylu czy istnieje jakaś różnica w zachowaniu? O ile mi wiadomo, zmienne są domyślnie inline.

Edytuj: Patrząc na wersję roboczą najnowszego standardu, używa ona również inline constexpr. W takim razie pytanie dotyczy właściwie normy.

+2

https://stackoverflow.com/a/38043566/2466431 – JVApen

+0

Zrobiliśmy dokładnie jeden "inline" w naszej dokumentacji szablonów zmiennych cech typu. 'is_integral_v' nie jest tym. –

Odpowiedz

4

[basic.link] /3.2 dotyczy nazw "nieinkresowej zmienna nielotnego typu const". Zmienny szablon nie jest zmienną, podobnie jak szablon klasy nie jest klasą, szablon funkcji nie jest funkcją, a narzędzie do wycinania plików cookie nie jest ciasteczkiem. Ta reguła nie ma zastosowania do samego szablonu o zmiennej wartości.

Zmienna szablon specjalizacja jest zmienną, więc istnieją pewne pytania dotyczące tego, czy ta reguła daje jej wewnętrzny związek. Jest to core issue 1713, którego kierunek jest taki, że reguła nie ma zastosowania.

Podstawowe wydanie 1713 nie zostało jednak rozwiązane w czasie dla C++ 17. Tak więc LWG zdecydowało się po prostu przykleić inline do wszystkich szablonów zmiennych, aby być bezpiecznym, ponieważ one również nie są bolesne.

12

[dcl.constexpr]/9

specyfikator constexpr wykorzystane w deklaracji obiektu deklaruje obiekt jako const.

[basic.link]/3.2

Nazwa mający zakres namespace ma wewnętrzny łącznik jeśli jest to nazwa

-a non-inline zmienna nielotnych const wykwalifikowanej typ, który nie jest jawnie zadeklarowanym zewnętrznym, ani nie został zadeklarowany wcześniej jako zewnętrzny łącznik

Bez specyfikatora inline, miałby wewnętrzny link. Może to być problematyczne, jeśli porównasz dwa wskaźniki do tej samej nazwy zmiennej w innej jednostce tłumaczeniowej.


Nota Bene: wbudowany specyfikator jest nadmiarowy z constexpr tylko wtedy, gdy zmienna jest statycznym elementem danych klasy.


następstwie exemple łatwego naruszeniem one definition rule że może się zdarzyć, jeśli is_integral_v gdzie nie inline.

bad_type_trait.h

template<class T> 
constexpr auto bad_is_integral_v=std::is_integral<T>::value; 

my_header.h

#include "bad_type_trait.h" 
void f(const bool& x); 

inline void g() 
    { 
    f(bad_is_integral_v<int>); 
    //g ODR use the static variable bad_is_integral_v. 
    //"ODR use" approximate definition is: 
    //  the variable is refered by its memory address. 
    } 

source1.cpp

#include "my_header.h" 
void my_func1(){ 
    g(); //the definition of g in this translation unit. 
    } 

source2.cpp

#include "my_header.h" 
void my_func2(){ 
    g(); //is not the same as the definition of g in this translation unit. 
    } 

W dwóch jednostkach tłumaczeniowych zmienna bad_is_integral_v jest tworzona jako oddzielne zmienne statyczne. Funkcja inline g() jest zdefiniowana w tych dwóch jednostkach tłumaczeniowych.Wewnątrz definicji g() zmienna bad_is_integral_v wykorzystuje ODR, więc dwie definicje g() są różne, co stanowi naruszenie zasady jednej definicji.

+3

Ale wiesz. To rodzi kolejne interesujące pytanie. Dlaczego, na litość, przyjmiemy adres stałej cechy typu? – StoryTeller

+3

A może nikt nie oczekuje, że ludzie przyjmą adres. Ponieważ 'std :: xxx <> :: value' będzie inline ze względu na bycie statycznym członkiem danych, wersja' xxx_v' jest również wbudowana, aby lepiej odwzorować ją. To może być tylko kwestia spójności. – StoryTeller

+2

@StoryTeller Być może przekazać go do jakiegoś ogólnego szablonu funkcji, który przyjmuje odniesienie do przekazywania? –