Tùy thuộc vào cách bạn sử dụng các mã này biểu thức không đổi.
Các ODR (quy tắc một nét) cho rằng
(§3.2/2) [...] Một biến có tên xuất hiện như một biểu hiện khả năng đánh giá lại là ODR-sử dụng trừ khi nó là một đối tượng đáp ứng các yêu cầu xuất hiện trong biểu thức không đổi (5.19) và chuyển đổi từ rvalue sang rvalue (4.1) được áp dụng ngay lập tức. [...]
(Và sau đó, rất nhiều quy tắc đặc biệt, ngoại lệ và ngoại lệ của ngoại lệ theo.)
Bất kỳ biến mà là ODR-sử dụng, phải có đúng một định nghĩa. Các biểu thức hằng số của bạn có một khai báo, nhưng không phải là một định nghĩa, vì vậy điều này diễn ra tốt trừ khi bạn sử dụng một trong số chúng.
Ví dụ, sau việc suôn sẻ:
int main() {
E e = GetE<float>::type;
return 0;
}
Nhưng điều này không:
void f(const E &)
{ }
int main() {
f(GetE<float>::type);
return 0;
}
vì f
đòi hỏi một (const) tài liệu tham khảo, vì vậy việc chuyển đổi giá trị trái-to-rvalue không thể áp dụng ngay lập tức, do đó điều này tạo thành một sử dụng odr. Trình biên dịch sẽ phàn nàn rằng nó bỏ lỡ một định nghĩa.
(Lưu ý: Như ShafikYaghmour đã tìm thấy (xem nhận xét), bạn có thể không nhận được đơn khiếu nại nếu trình biên dịch sử dụng tối ưu hóa vì các tham chiếu có thể được tối ưu hóa. tùy thuộc vào trình biên dịch).)
Để giải quyết vấn đề, định nghĩa bắt buộc có thể được cung cấp theo cách thông thường, tức làngoài struct nét:
constexpr E GetE<float>::type;
constexpr E GetE<char>::type;
constexpr E GetE<int>::type;
Nhưng vì đây sẽ phải xảy ra trong cpp (không phải là tập tin header), bạn sẽ kết thúc phải duy trì tờ khai và các định nghĩa ở hai nơi khác nhau, đó là rườm rà.
Các giải pháp bạn vừa đề xuất trong bình luận của bạn, ví dụ: xác định một constexpr (và inline) chức năng, âm thanh phải:
template <class T> constexpr E GetE();
template <> constexpr E GetE<float>()
{ return TYPE_FLOAT; }
template <> constexpr E GetE<char>()
{ return TYPE_CHAR; }
template <> constexpr E GetE<int>()
{ return TYPE_INT; }
void f(const E &)
{ }
int main() {
E e = GetE<float>();
f(GetE<float>());
return 0;
}
Điều này nghe có vẻ hợp lý. Tôi đã thay đổi để sử dụng một mẫu chức năng như 'tmpl E GetE()' và sau đó chuyên thay thế và điều này đã sửa nó. Cảm ơn. –
@jogojapan Tôi đang cố gắng tìm hiểu từ nhận xét của bạn nhưng tôi không thấy lỗi khi sử dụng đoạn mã cuối cùng: http://liveworkspace.org/code/4oTEis Tôi đang thiếu gì? Cảm ơn bạn –
@ShafikYaghmour Đó là vì cờ trình biên dịch '-O2'. Nó tối ưu hóa các tham chiếu đi. Tốt bình luận, mặc dù, tôi sẽ đề cập đến điều này trong câu trả lời. – jogojapan