2017-10-13 24 views
5

Tôi có một lớp Configkhông xác định tham chiếu đến int const trong shared_ptr

// config.hpp 

class Config { 
    public: 
    static constexpr int a = 1; 
    static constexpr int b = 1; 
} 

và bao gồm trong main.cpp

// main.cpp 
#include "config.hpp" 
int main() { 
    std::cout << Config::a << std::endl; // this is ok 
    std::shared_ptr<otherClass> stream = std::make_shared<otherClass>( 
Config::a); // compile error 
} 

và trình biên dịch nói rằng undefined reference to Config::a

và nó hoạt động khi sử dụng cout , nhưng không hoạt động khi bên trong hàm xây dựng shared_ptr.

Tôi không biết tại sao điều này lại xảy ra.

+0

Bạn cần phải xác định 'a' ở phạm vi không gian tên như một thành viên tĩnh trước khi C++ 17, tức là' constexpr int Config :: a; ' –

+0

Tại sao ' cout' hoạt động? –

+1

Đó là một kết quả không may của việc chuyển tiếp hoàn hảo và sử dụng odr khiến cho 'make_shared' không hoạt động. 'make_shared (int (Config :: a))' cũng sẽ hoạt động –

Trả lời

7

Lưu ý rằng std::make_shared mất thông số tham khảo, gây Config::aodr-used bởi vì nó sẽ được ràng buộc với thông số tham khảo, sau đó định nghĩa của nó ở phạm vi không gian tên được yêu cầu (trước C++ 17).

Mặt khác, std::cout << Config::a sẽ không gây ra Config::a được ODR được sử dụng, bởi vì std::basic_ostream::operator<< (int) mất thông số theo giá trị, Config::a là sau đó tùy thuộc vào giá trị trái-to-rvalue chuyển đổi yêu cầu để sao chép-khởi tạo các tham số, do đó Config::a là không sử dụng odr.

Nếu một đối tượng không được sử dụng, định nghĩa của nó phải tồn tại. Bạn có thể thêm định nghĩa (trong tệp triển khai) dưới dạng

constexpr int Config::a; // only necessary before C++17 

Lưu ý rằng nó không thể khởi tạo.

LIVE

Kể từ C++ 17 constexpr static data member được ngầm inline sau đó định nghĩa như vậy là không cần thiết nữa, do đó, mã của bạn hoạt động tốt từ C++ 17.

Nếu một thành viên static dữ liệu được khai báo constexpr, nó là ngầm inline và không cần phải được redeclared ở phạm vi không gian tên. Việc xác nhận lại này mà không có trình khởi tạo (trước đây được yêu cầu như được hiển thị ở trên) vẫn được cho phép nhưng không được chấp nhận.

LIVE

+0

Lưu ý rằng định nghĩa tại phạm vi không gian tên không thể có trong tệp tiêu đề; nó phải nằm trong tệp .cpp bạn liên kết với mọi thứ khác. –

1

một của bạn là tư nhân, và hoặc là một công cộng: cần preceed nó hay làm cho lớp một struct để có được công chúng mặc định. Nhưng điều này biên dịch dưới C++ 14 https://godbolt.org/g/tS4M1Z

#include <iostream> 
#include <memory> 

struct Config { 
    static constexpr int a = 1; 
    static constexpr int b = 1; 
}; 

struct otherClass { 
    otherClass(int c) { } 
}; 

int main() { 
    std::cout << Config::a << std::endl; // this is ok 
    std::shared_ptr<otherClass> stream = std::make_shared<otherClass>(Config::a); // compile error 
} 
+0

chỉnh sửa dưới dạng công khai. xin lỗi vì những lỗi lầm. –

+1

Có, vấn đề có thể thực sự phải làm với nhiều đơn vị dịch. Nếu hàm tạo cho otherClass nằm trong một tệp cpp khác, thì điều này sẽ không hoạt động trong C++ 14. –

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