2013-04-25 9 views
9

Podczas próby skompilowania następującego kodu pojawia się błąd łącznika: Undefined symbols for architecture x86_64: "Foo()", referenced from: _main in main.o przy użyciu LLVM 4.2.Niezdefiniowane symbole funkcji constexpr

To zachowanie występuje tylko wtedy, gdy funkcja jest oznaczona jako constexpr. Program kompiluje i łączy poprawnie, gdy funkcja jest oznaczona jako const. Dlaczego deklarowanie funkcji powoduje błąd linkera?

(zdaję sobie sprawę, że pisanie funkcji w ten sposób nie daje korzyści z obliczeń kompilacji;. W tym momencie jestem ciekaw dlaczego funkcja nie odwołuje)

main.cpp

#include <iostream> 
#include "test.hpp" 

int main() 
{ 
    int bar = Foo(); 
    std::cout << bar << std::endl; 

    return 0; 
} 

test.hpp

constexpr int Foo(); 

test.cpp

#include "test.hpp" 

constexpr int Foo() 
{ 
    return 42; 
} 
+0

Zobacz http://stackoverflow.com/questions/14391272/does-constexpr-imply-inline –

Odpowiedz

8

Why does declaring the function constexpr cause a linker error?

To dlatego constexpr funkcje są niejawnie inline. Zgodnie z pkt 7.1.5/2 C++ 11 Standard:

A constexpr specifier used in the declaration of a function that is not a constructor declares that function to be a constexpr function. Similarly, a constexpr specifier used in a constructor declaration declares that constructor to be a constexpr constructor. constexpr functions and constexpr constructors are implicitly inline (7.1.2).

zgodnie z pkt 7.1.2/4, a następnie:

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [...]

+0

'inline' nie ma żadnego wpływu na wiązanie. (Jest prawdopodobne, że 'constexpr' ma, biorąc pod uwagę jego związek ze stałą w ogóle, ale nie ma nic w podanej sekcji, która by to wskazała.) –

+0

@JamesKanze: Zmieniono, dziękuję –

+0

@JamesKanze: 7.1.5 mówi" The Specifier 'constexpr' nie ma wpływu na typ funkcji constexpr lub konstruktor constexpr." i (język) powiązanie jest częścią typu funkcji (7.5). Tak więc wydaje się, że ogranicza to wpływ 'constexpr' na połączenie. –

1

To ciekawe pytanie. Jak Andy Prowl, constexpr tworzy funkcję inline, co oznacza, że ​​musi ona być zdefiniowana jako w każdej jednostce tłumaczeniowej, która jej używa; Spodziewałbym się błędu z kompilatora. (Faktycznie, jeśli czytam §3.2/5 prawidłowo, diagnostyczny jest wymagane w przypadku korzystania z funkcji i nie ma definicji.)

Jako dlaczego const ma inny problem: nie można oznaczyć niebędącego -menber function const. Jeśli napiszesz const int Foo();, , to nie jest to funkcja, która jest const, ale typ, który zwraca (z wyjątkiem tego, że jeśli typ powrotu nie jest typem klasy, to kwalifikatory cv są ignorowane, więc jest to naprawdę to samo, co int Foo();) .

5

Ciało funkcji constexpr musi być widoczne w każdym punkcie, w którym jest używane. W twoim przypadku musisz mieć kod move Foo() do test.hpp.

Na przykład, należy rozważyć ten kod w main.cpp:

constexpr int Foo(); 

int main() { 
    static_assert(Foo() == 42, "Ops"); 
} 

gdzie Foo() jest zdefiniowana w test.cpp. W jaki sposób kompilator powinien sprawdzić stan static_assert podczas przetwarzania main.cpp, jeśli nie może zobaczyć, że Foo() zwraca 42. To niemożliwe. Cały sens funkcji constexpr polega na tym, że kompilator może "wywoływać" je w czasie kompilacji i aby tak się stało, musi zobaczyć kod.

Dlatego ten kompiluje grzywny:

constexpr int Foo() { return 42; } 

int main() { 
    static_assert(Foo() == 42, "Ops"); 
} 
+0

+1 Dziękuję za wzmianka o 'static_assert'. To sprawia, że ​​przyczyna mojego problemu jest o wiele bardziej oczywista. – Aurelius