2013-04-25 57 views
9

Khi tôi cố gắng biên dịch mã sau, tôi nhận được lỗi liên kết: Undefined symbols for architecture x86_64: "Foo()", referenced from: _main in main.o sử dụng LLVM 4.2.Ký hiệu không xác định cho hàm constexpr

Hành vi này chỉ xảy ra khi hàm được đánh dấu constexpr. Chương trình biên dịch và liên kết chính xác khi chức năng được đánh dấu const. Tại sao việc khai báo hàm constexpr gây ra lỗi liên kết?

(Tôi nhận ra rằng văn bản cho chức năng theo cách này không cung cấp cho các lợi ích của việc biên dịch-thời gian tính toán;. Tại thời điểm này tôi tò mò tại sao chức năng thất bại trong việc liên kết)

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

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

Trả lời

8

Why does declaring the function constexpr cause a linker error?

Đó là bởi vì constexpr chức năng đang ngầm inline. Mỗi khoản 7.1.5/2 của C++ 11 Tiêu chuẩn:

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).

mỗi khoản 7.1.2/4, sau đó:

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' không có bất kỳ ảnh hưởng đến liên kết. (Nó có khả năng 'constexpr' không, cho mối quan hệ của nó với const nói chung, nhưng không có gì trong phần mà bạn trích dẫn mà sẽ chỉ ra điều này.) –

+0

@JamesKanze: Đã chỉnh sửa, cảm ơn bạn –

+0

@JamesKanze: 7.1.5 nói" The 'constexpr' specifier không có e ff ect về kiểu hàm constexpr hoặc hàm tạo constexpr." và (ngôn ngữ) liên kết là một phần của một loại chức năng (7.5). Vì vậy, có vẻ như sẽ hạn chế bất kỳ hiệu ứng 'constexpr' trên liên kết. –

1

Đó là một câu hỏi thú vị. Như Andy Prowl, constexpr làm cho chức năng inline, có nghĩa là phải có định nghĩa của nó trong mọi đơn vị dịch sử dụng nó; Tôi đã mong đợi một lỗi từ trình biên dịch. (Trên thực tế, nếu tôi đọc §3.2/5 một cách chính xác, một chẩn đoán là cần thiết nếu bạn sử dụng chức năng và không có định nghĩa.)

Là tại sao const có hành vi khác nhau: bạn không thể đánh dấu một tổ chức phi chức năng -menber const. Nếu bạn viết const int Foo();, , đó không phải là chức năng là const, nhưng loại trả về (ngoại trừ việc loại trả về không phải là loại lớp, vòng loại cv bị bỏ qua, vì vậy điều này thực sự giống như int Foo();) .

5

Phần thân của hàm constexpr phải hiển thị ở mọi thời điểm được sử dụng. Trong trường hợp của bạn, bạn phải có mã số move Foo() để test.hpp.

Ví dụ, hãy xem xét mã này trong main.cpp:

constexpr int Foo(); 

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

nơi Foo() được định nghĩa trong test.cpp. Làm thế nào trình biên dịch có nghĩa vụ phải kiểm tra các điều kiện static_assert trong khi xử lý main.cpp nếu nó không thể thấy rằng Foo() không trở lại 42. Không thể nào. Toàn bộ các điểm của hàm constexpr là trình biên dịch có thể "gọi" chúng tại thời gian biên dịch và để điều này xảy ra, nó phải xem mã.

Vì vậy, điều này biên dịch tốt:

constexpr int Foo() { return 42; } 

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

+1 Cảm ơn bạn đã đề cập đến 'static_assert'. Điều đó làm cho nguyên nhân của vấn đề của tôi rõ ràng hơn nhiều. – Aurelius