2015-11-27 16 views
5

Xét đoạn mã sau:Loại chuyển đổi ở mẫu phi kiểu lập luận mà không constexpr

struct A { 
    constexpr operator int() { return 42; } 
}; 

template <int> 
void foo() {} 

void bar(A a) { 
    foo<a>(); 
} 

int main() { 
    foo<A{}>(); 

    const int i = 42; 
    foo<i>(); // (1) 

    A a{}; 

    static_assert(i == a, ""); 
    bar(a); 
    foo<a>(); // error here 
} 

Clang 3.7 với C++ 14 chấp nhận này, trong khi gcc 5.2.0 với C++ 14 không, sản xuất thông báo sau:

/tmp/gcc-explorer-compiler1151027-68-1f801jf/example.cpp: In function 'int main()': 
26 : error: the value of 'a' is not usable in a constant expression 
foo<a>(); 
^ 
23 : note: 'a' was not declared 'constexpr' 
A a{}; 
^ 
Compilation failed 

Thay đổi aconstexpr theo đề nghị của gcc sửa chữa các lỗi biên dịch gcc, nhưng không constexpr, mà compi ler là đúng?

Đối với tôi, có vẻ như a phải là "có thể sử dụng được trong biểu thức liên tục", như là static_assert ceritifies. Hơn nữa, thực tế là i có thể được sử dụng theo cùng một cách (được đánh dấu (1)) và thực tế là biên dịch bar(), cũng khiến tôi nghĩ rằng gcc là sai.

UPD: Báo cáo một lỗi đối với gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68588

+0

thay đổi 'const' bởi 'công trình constexpr' [ Demo] (http://coliru.stacked-crooked.com/a/1bc480f2de523b5e). – Jarod42

+0

@ Jarod42, vâng, hãy xem bản chỉnh sửa của tôi. – Petr

Trả lời

5

Chuyển đổi do người dùng xác định được cho phép bởi [expr.const]/(4.1) và tôi không thấy một dấu đầu dòng có thể áp dụng trong [expr.const]/2 có thể ngăn biểu thức của bạn không bị thay đổi. Trong thực tế, các yêu cầu rất lỏng lẻo rằng tuyên bố a như

A a; 

still giving a well-formed program, ngay cả khi a không có một constructor mặc định constexpr vv kể từ khi các nhà điều hành chuyển đổi là constexpr và không có thành viên được đánh giá.

Như bạn thấy mình, GCC mâu thuẫn ở chỗ nó cho phép a trong điều kiện static_assert nhưng không phải là đối số mẫu.

+0

Vì vậy, đó là lỗi gcc? – Petr

+1

@Petr Chắc chắn. – Columbo

-2

Như @ Jarod42 gợi ý a nên constexpr. Điều này là do các mẫu được suy ra tại thời gian biên dịch, và do đó các đối số không phải kiểu cũng phải có sẵn tại thời gian biên dịch. constexpr là một lời hứa rằng họ sẽ có sẵn tại thời gian biên dịch.

+0

Tôi hoàn toàn nhận thức được thực tế là 'constexpr' giải quyết được vấn đề (xem thêm phần chỉnh sửa của tôi). – Petr

+0

Nếu có, thì điều này sẽ cho bạn biết triển khai nào là chính xác. –

2

Tôi sẽ nói rằng Clang là chính xác.

Dự thảo hiện tại C++ (n4296) nói:

luận 14.3.2 Mẫu phi loại [temp.arg.nontype]

Mẫu đối số cho một tổ chức phi kiểu mẫu tham số phải là một biểu thức hằng số chuyển đổi (5.20) của kiểu mẫu tham số

Và 5,20 §4 nói (nhấn mạnh của tôi):

5.20 Biểu thức không đổi [expr.const]

...

(4) Một chuyển đổi biểu thức hằng số của loại T là một biểu hiện, ngầm chuyển đổi sang loại T, nơi chuyển biểu thức là một biểu thức hằng và trình tự chuyển đổi ngầm chỉ chứa

(4,1) - chuyển đổi người dùng định nghĩa, ...

IFAIK trong foo<a>(); một được chuyển thành int với một constexpr chuyển đổi người dùng định nghĩa và như vậy một biểu thức hằng chuyển đổi.

đó đang được nói, chúng tôi không xa một trường hợp cạnh đây, và lời khuyên của tôi sẽ là: không chơi với một cấu trúc như vậy trong mã sản xuất :-)

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