2017-10-01 17 views
28

W odniesieniu do this question. Stała stała ekspresja użyta do zainicjowania zmiennej constexpr jest źle sformułowana. Tyle jest danych.Dlaczego nie, jeśli constexpr spowoduje, że błąd rdzenia stałego wyrażenia zniknie?

Ale gdy próbuję włączyć if się z if constexpr:

template <typename T> 
void foo() { 
    constexpr int x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1 << x; 
    } 
} 

int main(){ 
    foo<int>(); 
} 

błąd będzie się powtarzał. GCC 7.2 nadal daje:

error: right operand of shift expression '(1 << -1)' is negative [-fpermissive] 

Ale myślałem, że semantyczny kontrola powinna być pozostawiona unpreformed na porzuconego gałęzi.

Dokonywanie zadnie poprzez constexpr lambda nie pomaga jednak:

template <typename T> 
void foo(){ 
    constexpr int x = -1; 
    constexpr auto p = []() constexpr { return x; }; 
    if constexpr (x >= 0){ 
     constexpr int y = 1<<p(); 
    } 
} 

constexpr specifier na y wydaje się zmieniać jak zaznaczone jest odrzucane oddział. Czy to jest zamierzone zachowanie?


@ max66 był na tyle uprzejmy, by sprawdzić inne implementacje. Zgłasza, że ​​błąd jest powtarzalny zarówno w GCC (7.2.0/Head 8.0.0), jak i Clang (5.0.0/Head 6.0.0).

+0

Brzmi jak błąd kompilatora. Czy próbowałeś innej implementacji? –

+1

@ShacharShemesh - Ja sam nie. Ale PO posta, które łączyłem, informuje, że [Clang i MSVC zachowują się tak samo] (https://stackoverflow.com/questions/46510531/undefined-behavior-when-constexpr-evaluating-negative-bitshift#comment79975550_46510531). – StoryTeller

+2

Potwierdzam problem z clang ++ 3.8.1 – max66

Odpowiedz

18

Norma nie mówi wiele o odrzuconym oświadczeniu z if constexpr. Zasadniczo istnieją dwa stwierdzenia w [stmt.if] na temat:

  1. W załączonym szablonie odrzuconych instrukcji nie są tworzone instancje.
  2. Nazwy, do których odwołuje się odrzucona instrukcja, nie są wymagane, aby zdefiniować ODR.

Żadna z poniższych nie ma zastosowania do użytkownika: kompilatory prawidłowo narzekają na constexpr w przypadku inicjalizacji. Zauważ, że musisz uzależnić warunek od parametru szablonu, jeśli chcesz skorzystać z instancji z instancją, aby zakończyć się niepowodzeniem: jeśli wartość nie zależy od parametru szablonu, niepowodzenie nastąpi, gdy szablon ma wartość zdefiniowany jako .Na przykład, ten kod nie powiedzie:

template <typename T> 
void f() { 
    constexpr int x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1<<x; 
    } 
} 

Jeśli jednak zrobić x zależy od rodzaju T to jest OK, nawet kiedy f jest tworzony z int:

template <typename T> 
void f() { 
    constexpr T x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1<<x; 
    } 
} 
int main() { 
    f<int>(); 
} 
+0

Kiedy komentuję Kerrek, przykład w moim poście jest słaby. Sprawdziłem, czy nie zniknęło po przeniesieniu kodu do szablonu. W przypadku podstawowym nadal występuje błąd. Indirect nie. Zaktualizowałem MCVE. Przepraszam za niedogodności. – StoryTeller

+2

@StoryTeller: Zaktualizowałem moją odpowiedź, aby wyjaśnić, że dotyczy to tylko * wystąpienia * szablonu. Błąd pojawia się podczas * definicji * szablonu! –

+0

@ DietmarKühl: Bardzo dobry punkt - sprawdzenie niezespolonych konstrukcji jest częścią definicji szablonu, a nie jednej instancji szablonu, więc brak instancjonowania odrzuconej ręki jest w rzeczywistości czerwonym śledziem. –

5

Nie jestem pewien, dlaczego spodziewasz się, że oddział nie zostanie sprawdzony. Jedynym razem, jeśli oddział „nie jest zaznaczone” jest wtedy, gdy jest on częścią szablonu i nie instancja, zgodnie [stmt.if] p2:

Podczas instancji zamykającego matrycy podmiot (Klauzula 17), jeżeli warunek nie jest zależny od wartości po jego utworzeniu, odrzucona subwencja (jeśli występuje) nie jest tworzona.

Twój kod nie wydaje się mieć takiej sytuacji.

+1

Przyznaję, że moja [mcve] jest biedna. [Jednak błąd nadal występuje po przeniesieniu kodu do szablonu] (https://wandbox.org/permlink/ASFlaJjyMbXqfRtt) (nie w przypadku lambda). Więc będę aktualizować moje pytanie. Przepraszamy za unieważnienie tej odpowiedzi. – StoryTeller

+3

@StoryTeller: Bez obaw. Dobrze jest zgłębić nowe funkcje, takie jak to. –

10

Zauważ, że na rachunku odrzucone przez: Constexpr If:

odrzucone oświadczenie nie może być źle sformułowane dla każdej możliwej specjalizacji:

Aby naprawić problem, możesz wydać polecenie w zależności od parametru szablonu, np.

template<typename T, int X> struct dependent_value { constexpr static int V = X; }; 

template <typename T> 
void foo() { 
    constexpr int x = -1; 
    if constexpr (x >= 0){ 
     constexpr int y = 1 << dependent_value<T, x>::V; 
    } 
} 

LIVE

Powiązane problemy