2014-09-27 23 views
8

Tôi có sau C++ 11 mã (phiên bản đơn giản):Khi nào một thành viên lớp constexpr tĩnh cần định nghĩa ngoài lớp?

struct Info 
{ 
    const char * name; 
    int version; 
}; 

class Base 
{ 
public: 
    const Info info; 
    Base (Info info) : info (info) {} 
}; 

class Derived : public Base 
{ 
public: 
    static constexpr Info info = {"Foobar", 2}; 
    Derived() : Base (info) {} 
}; 

int main() 
{ 
    static Derived derived; 
    return 0; 
} 

GCC 4.9.1 biên dịch và liên kết đang tốt này. Clang 3.5.0, mặt khác, than phiền về một tham chiếu không xác định:

/tmp/test-109c5c.o: In function `main': 
test.cc:(.text+0x1c): undefined reference to `Derived::info' 
test.cc:(.text+0x22): undefined reference to `Derived::info' 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Điều gì đúng? Mã này có hợp pháp hay không? Sự hiểu biết của tôi về các quy tắc liên quan đến các thành viên constexpr tĩnh (chủ yếu dựa trên this question) là một định nghĩa out-of-class là cần thiết chỉ khi địa chỉ của biến được thực hiện. Nhưng tôi không lấy địa chỉ của Derived :: info hoặc sử dụng một tham chiếu đến nó ở bất cứ đâu; Tôi chỉ truyền nó theo giá trị cho hàm tạo Base.

cách giải quyết khác nhau mà tôi đã tìm thấy:

  • Hãy cả nhà xây dựng (Base và nguồn gốc) constexpr. Điều này có thể hoặc không thể là một lựa chọn với các lớp thực, phức tạp hơn các lớp trong ví dụ. Tôi sẽ thử nó, anyway.
  • Khai báo cá thể của Nguồn gốc có nguồn gốc tự động thay vì thời lượng tĩnh. Đây không phải là một tùy chọn cho dự án thực: lớp Derived là một thực thi plugin, và một thể hiện của nó cần được xuất khẩu như một biểu tượng công khai trong một đối tượng được chia sẻ.
  • Xóa nguồn gốc :: thông tin hoàn toàn và gọi hàm tạo cơ sở bằng đối tượng tạm thời được khởi tạo cú đúp thay vào đó, tức là Base ({"Foobar", 2}). Giải pháp này sẽ làm việc, nhưng nó xấu xí (theo ý kiến ​​của tôi) khi các thành viên được thêm vào struct Info.
+1

Bản sao có thể có của [vector :: push_back odr-sử dụng giá trị, khiến tham chiếu không xác định đối với thành viên lớp tĩnh] (http://stackoverflow.com/questions/272900/undefined-reference-to-static-class-member) –

+0

Điều gì về việc làm cho nó thành một chức năng thành viên thay vì thành viên dữ liệu? – imreal

+0

@ πάνταῥεῖ Tôi không sử dụng std :: vector, nhưng liên kết của bạn đưa tôi đi đúng hướng. Cảm ơn! –

Trả lời

2

Aha, có vẻ như vấn đề là hàm xây dựng sao chép ngụ ý Info(const Info &). Để chuyển tham chiếu const Info & tới hàm tạo đó, cần phải lấy địa chỉ của Derived :: info.

Rõ ràng GCC tích cực hơn Clang trong việc tối ưu hóa trình tạo bản sao. Nếu tôi sử dụng -fno-elide-constructors, thì GCC cũng khiếu nại về một tham chiếu không xác định đối với thông tin Derived ::.

Trong mọi trường hợp, khai báo các hàm tạo Base và Derived như constexpr dường như thực hiện những gì tôi muốn xảy ra ở đây, là Base :: info được khởi tạo tại thời gian biên dịch, thay vì được sao chép từ một thông tin Derived :: thời gian chạy.

Các vấn đề liên quan