2016-07-11 32 views
21

P0292R1 constexpr if został included, na ścieżce dla C++ 17. Wydaje się przydatna (i może zastąpić użycie SFINAE), ale komentarz odnośnie static_assert jest źle sformułowane, nie diagnostyczny wymagane w fałszywym gałęzi mnie przeraża:constexpr if i static_assert

Disarming static_assert declarations in the non-taken branch of a 
constexpr if is not proposed. 

void f() { 
    if constexpr (false) 
    static_assert(false); // ill-formed 
} 

template<class T> 
void g() { 
    if constexpr (false) 
    static_assert(false); // ill-formed; no 
       // diagnostic required for template definition 
} 

Rozumiem, że jest to całkowicie zabronione w użyciu static_assert wewnątrz constexpr jeśli (przynajmniej fałszywa/niepobrana gałąź, ale w praktyce oznacza to, że nie jest to bezpieczne ani użyteczne).

Jak to się dzieje ze standardowego tekstu? W tekście propozycji nie znalazłem żadnej wzmianki o static_assert, a funkcje constexpr w C++ 14 zezwalają na static_assert (szczegóły na cppreference: constexpr).

Czy ukrywa się w tym nowym zdaniu (po 6.4.1)? :

Kiedy constexpr if pojawia się w matrycy podmiotu, podczas konkretyzacji szablonu otaczającej lub rodzajowy lambda, porzucony oświadczenie nie jest tworzony.

Stamtąd, zakładam, że jest również zakazane, bez diagnostyki konieczne, aby wywołać inne constexpr (szablon) funkcje, które gdzieś dół wykresu połączeń może wezwać static_assert.

Konkluzja:

Jeśli moje rozumienie jest poprawne, nie dość, że umieścić sztywny limit na bezpieczeństwo i przydatność constexpr if jak mielibyśmy wiedzieć (z dokumentacji lub inspekcji kodu) o dowolnej korzystanie z static_assert? Czy moje zmartwienia są błędne?

Aktualizacja:

Ten kod kompiluje bez ostrzeżenia (głową clang 3.9.0), ale jest moim rozumieniu źle sformułowane, nie wymaga diagnostyki. Ważny czy nie?

template< typename T> 
constexpr void other_library_foo(){ 
    static_assert(std::is_same<T,int>::value); 
} 

template<class T> 
void g() { 
    if constexpr (false) 
    other_library_foo<T>(); 
} 

int main(){ 
    g<float>(); 
    g<int>(); 
} 
+1

To źle sformułowane, ponieważ warunek jest fałszywy. Nie dlatego, że jest wewnątrz constexpr, jeśli ... – immibis

+3

@immibis. Oczywiste jest, że chodzi o nieprzyjętą gałąź, więc nie rozumiem, co konkretnie masz na myśli. Czy starasz się opracować i zinterpretować w kategoriach pytania końcowego? –

+0

clang już zaimplementowano 'if constexpr'. Jeśli masz jakiekolwiek wątpliwości, dlaczego nie spróbować [wypróbować go sam] (http://melpon.org/wandbox/permlink/8AmTzaSIIUi4M1kY)? – cpplearner

Odpowiedz

18

To jest mówienie o ugruntowanej rule dla szablonów - ta sama reguła, która pozwala kompilatorom zdiagnozować template<class> void f() { return 1; }. [temp.res]/8 z nowym zmiany pogrubione:

Program jest źle sformułowane, nie diagnostyczny wymagane, jeśli:

  • nie obowiązuje specjalizacja może być generowany przez matrycę lub substatement z constexpr if rachunku ([stmt.if]) w obrębie szablonu oraz szablonie nie jest tworzony, lub
  • [...]

Nie można wygenerować ważnej specjalizacji dla szablonu zawierającego static_assert, którego stan jest niezależny i wynosi false, więc program jest źle sformułowanym raportem NDR.

static_assert s z warunkiem zależnym, który można ocenić na true dla co najmniej jednego typu, nie ma to wpływu.

+0

Dziękuję szczególnie za link do wersji roboczej. Ma to sens, ponieważ ocenianie nieprawidłowych szablonów może być dowolnie trudne. –

+0

Jeszcze raz dziękuję. Przyjęty. Warto zauważyć, że linie, które zacytowałeś, są w pierwotnej propozycji, do której się przyłączyłem, ale za nimi tęskniłem. –

+0

Pomocnik, aby ustawić liczbę parametrów fałszywego szablonu: template < typename > constexpr bool false_c = false; –

2

Edit: Trzymam to self-odpowiedź z przykładami i bardziej szczegółowe wyjaśnienia nieporozumień, które prowadzą do tego pytania. Krótka odpowiedź T.C. jest wystarczająco ścisłe.

Po ponownym przeczytaniu wniosku i static_assert w current draft i wnioskuję, że moje obawy były błędne. Przede wszystkim należy tutaj podkreślić szablon definicja.

źle uformowany; nie diagnostyczne konieczne do definicji szablonu

Jeśli szablon jest instancja każdy static_assert ogień zgodnie z oczekiwaniami.To prawdopodobnie dobrze pasuje do stwierdzenia, które cytowałem:

... odrzucona instrukcja nie jest tworzona.

To jest trochę niejasne dla mnie, ale wnioskuję, że oznacza to, że szablony występujące w odrzuconej oświadczenie nie zostanie instancja. Inny kod musi jednak być poprawny pod względem składniowym. static_assert(F) [gdzie F jest fałszywy, albo dosłownie albo wartość constexpr] wewnątrz odrzucono if constexpr klauzuli będzie zatem nadal „kęs”, gdy szablon zawierający static_assert jest tworzony. Lub (nie jest wymagane, na łasce kompilatora) już przy deklaracji, jeśli wiadomo, że zawsze jest fałszywa.

Przykłady: (live demo)

#include <type_traits> 

template< typename T> 
constexpr void some_library_foo(){ 
    static_assert(std::is_same<T,int>::value); 
} 

template< typename T> 
constexpr void other_library_bar(){ 
    static_assert(std::is_same<T,float>::value); 
} 

template< typename T> 
constexpr void buzz(){ 
    // This template is ill-formated, (invalid) no diagnostic required, 
    // since there are no T which could make it valid. (As also mentioned 
    // in the answer by T.C.). 
    // That also means that neither of these are required to fire, but 
    // clang does (and very likely all compilers for similar cases), at 
    // least when buzz is instantiated. 
    static_assert(! std::is_same<T,T>::value); 
    static_assert(false); // does fire already at declaration 
          // with latest version of clang 
} 

template<class T, bool IntCase> 
void g() { 
    if constexpr (IntCase){ 
    some_library_foo<T>(); 

    // Both two static asserts will fire even though within if constexpr: 
    static_assert(!IntCase) ; // ill-formated diagnostic required if 
           // IntCase is true 
    static_assert(IntCase) ; // ill-formated diagnostic required if 
           // IntCase is false 

    // However, don't do this: 
    static_assert(false) ; // ill-formated, no diagnostic required, 
          // for the same reasons as with buzz(). 

    } else { 
    other_library_bar<T>(); 
    }  
} 

int main(){ 
    g<int,true>(); 
    g<float,false>(); 

    //g<int,false>(); // ill-formated, diagnostic required 
    //g<float,true>(); // ill-formated, diagnostic required 
} 

standardowy tekst na static_assert jest nadzwyczaj krótki. W standardese, jest to sposób, aby program źle sformułowane z diagnostyki (jak @immibis również podkreślić):

7.6 ... Jeżeli wartość wyrażenia, gdy tak przekształcany jest prawdą, deklaracja nie ma żadnego efektu. W przeciwnym razie program jest źle sformułowane i otrzymany komunikat diagnostyczny (1.4) zawiera tekst string-dosłowny, jeśli ktoś jest dostarczany ...

Powiązane problemy