Tôi đang thử nghiệm với các hàm constexpr trong C++ 14. Các mã sau đây, mà sẽ tính toán các công trình thừa như mong đợi:C++ 14: suy ra (tự động) các kiểu trả về từ constexpr với các biểu thức bậc ba
template <typename T>
constexpr auto fact(T a) {
if(a==1)
return 1;
return a*fact(a-1);
}
int main(void) {
static_assert(fact(3)==6, "fact doesn't work");
}
khi nó được biên soạn như sau với kêu vang:
> clang++ --version
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
> clang++ -std=c++14 constexpr.cpp
Tuy nhiên, khi tôi thay đổi fact
định nghĩa để sử dụng ?
hành ternary:
template <typename T>
constexpr auto fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
tôi nhận được lỗi biên dịch sau:
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:12:31: fatal error: recursive template instantiation exceeded maximum depth of
256
return a==T(1) ? T(1) : a*fact(a-1);
... snip ...
constexpr.cpp:16:19: note: in instantiation of function template specialization 'fact<int>'
requested here
static_assert(fact(3)==6, "fact doesn't work");
Vấn đề là cố định nếu tôi một cách rõ ràng nêu rõ kiểu trả về T (thay vì sử dụng ô tô để suy ra kiểu trả về)
template <typename T>
constexpr T fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
Nếu tôi loại bỏ các tham số mẫu, mô hình được lặp lại (phiên bản ternary thất bại, và phiên bản if
làm việc)
// this works just fine
constexpr auto fact(int a) {
if(a==1)
return 1;
return a*fact(a-1);
}
trong khi điều này không
constexpr auto fact(int a) {
return a==1 ? 1 : a*fact(a-1);
}
với lỗi sau
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:16:25: error: function 'fact' with deduced return type cannot be used before it
is defined
return a==1 ? 1 : a*fact(a-1);
^
constexpr.cpp:15:16: note: 'fact' declared here
constexpr auto fact(int a) {
^
constexpr.cpp:20:26: error: invalid operands to binary expression ('void' and 'int')
static_assert(fact(3)==6, "fact doesn't work");
~~~~~~~^ ~
2 errors generated.
Điều gì đang xảy ra ở đây?
các phiên bản nếu có hai báo cáo trở lại. Liệu trình biên dịch sử dụng/tiêu chuẩn xác định một số loại evaulation lười biếng, nơi mà nó chỉ xem xét các báo cáo trở lại trong khối nếu khi một == 1? Nếu không, chúng tôi sẽ có cùng một vấn đề với cả hai phiên bản. – bcumming
Cảm ơn @Praetorian. Tôi có thể tự tìm kiếm (mặc dù tôi không phải là một luật sư ngôn ngữ). – bcumming
@Praetorian Nó không phải là trái ngược với những gì bạn tuyên bố trước đó. Kiểu trả về được suy ra cho mỗi câu lệnh return, nhưng một khi nó được suy ra cho câu lệnh trả về * any *, kiểu trả về được biết và có thể được sử dụng như một phần của việc khấu trừ các câu lệnh trả về sau. Lý do ví dụ của bạn với 'template' không thành công là vì kiểu trả về 'thực tế là ' được biết không nói gì về kiểu trả về 'thực tế ', nhưng nó là 'thực tế ' gọi 'thực tế 'trong mã OP . –
hvd