2016-01-21 14 views
5

Poniższy fragment kodu został pomyślnie skompilowany z gcc 5.3.0, ale nie udało się skompilować z clang 3.7.0. Użyłem kompilatorów online coliru z tymi samymi opcjami wiersza poleceń w obu przypadkach: -std = C++ 14 -O2 -Wall -pedantic -pthread.Argument używany tylko w nieocenionym kontekście w ciele funkcji constexpr

#include <cstdio> 

// Definition of constexpr function 'foo'. 
constexpr std::size_t foo(const int& arg_foo) { return sizeof(arg_foo); } 

// Definition of function 'test'. 
void test(const int& arg) 
{ 
    // The following line produces an error with clang. 
    constexpr std::size_t res_foo = foo(arg); 

    // Print the result returned by the 'foo' function. 
    std::printf("res_foo = %lu\n", res_foo); 
} 

// Definition of function 'main'. 
int main(int argc, const char* argv[]) 
{ 
    // Test function call. 
    test(argc); 

    // Return statement. 
    return 0; 
} 

dzyń odrzuca je z powodu następującego błędu:

error: constexpr variable 'res_foo' must be initialized by a constant expression 
constexpr size_t res_foo = foo(arg); 
          ~~~~^~~~ 

Z powodu tej różnicy pomiędzy tymi dwoma kompilatorów, zastanawiam się, czy jest to ważny kawałek kodu. Jeśli nie, chciałbym lepiej zrozumieć, dlaczego tak się dzieje.

+0

gcc bug, jeden z wielu, jeśli chodzi o constexpr – TemplateRex

+0

@TemplateRex Ale w jaki sposób 'foo' łamie którąkolwiek z zasad funkcji constexpr? – Archimaredes

+0

@Archimaredes nie, błąd polega na tym, że 'arg' w' teście' nie jest 'constexpr' – TemplateRex

Odpowiedz

1

Łącznie wartości const i constexpr. Definicja constexpr jest wartością znaną w czasie kompilacji. Ale zmienna argc jest znana tylko w czasie wykonywania (jest to liczba argumentów przekazywanych do pliku wykonywalnego). Nie można go przypisać do innej zmiennej constexpr - . Usunięcie constexpr z definicji res_foo spowoduje, że Twój kod będzie kompilowany.

Różnica między const i constexpr można uprościć do czegoś takiego:
const - Nie zamierzam zmienić tę wartość
constexpr - Wartość ta jest znany w czasie kompilacji i nie będę aby go zmienić

Domyślam się, że GCC jest w stanie skompilować ten kod z O2, ponieważ nie używasz argumentu arg_foo, a jego rozmiar jest znany w czasie kompilacji. Ale nadal jest niepoprawna pod względem składni - kompilator powinien wysyłać błąd, ponieważ wartość niebędąca constexpr jest przypisana do zmiennej constexpr.

+1

Myślę, że jest tego świadomy, jego pytanie jest takie, że nigdy nie używa on wartości' argc', po prostu bierze rozmiar. ', co jest wyrażeniem stałym. – TartanLlama

+0

@TartanLlama, czemu gcc jest w stanie skompilować ten kod z O2: ignoruje argument, ponieważ nie jest używany i zwraca dobrze znaną wartość podczas kompilacji. Ale nadal jest niepoprawna pod względem składni - kompilator powinien wysyłać błąd, ponieważ wartość inna niż "konwertowana" jest przypisana do zmiennej "constexpr". – DennisS

+0

Wiem, że to nadal jest niepoprawne składniowo, ale myślę, że to właśnie powinniście odpowiedzieć w odpowiedzi. – TartanLlama

0

Program jest dobrze sformułowany, ponieważ foo(arg) jest stałym wyrażeniem rdzeniowym zdefiniowanym w C++ 14 5.20/2. W szczególności nie ma konwersji l-wartość do r-wartości podczas oceny, co spowodowałoby, że nie stała się ona wyrażeniem.

+0

Niezupełnie. Oceniając, że wymaga oceny * Id-wyrażenie * 'arg', która biegnie w konflikt z [expr.const] /2.9„Warunkowe ekspresja e jest podstawowym wyrazem stała chyba oceny e, zgodnie z regułami streszczenie machine (1.9), oceni jedno z następujących wyrażeń: [...] wyrażenie id, które odnosi się do zmiennej lub elementu danych typu referencyjnego, chyba że referencja ma poprzednią inicjalizację i albo - jest inicjalizowana z ciągłym wyrażeniem lub - jest niestatycznym elementem danych obiektu, którego żywotność rozpoczęła się w trakcie oceny e ". –

+0

5/8 "Nieznany operand nie jest oceniany." – aschepler

+0

Tak, nie jest oceniany wewnątrz 'foo'.Ale jest ona oceniana poza nią w celu przekazywania argumentów. Pierwszym krokiem oceny 'foo (arg)' jest ocena 'foo' i' arg'. –

Powiązane problemy