2017-07-31 18 views
5

Tôi muốn tính giá trị e tại thời gian biên dịch (đừng lo lắng, không phải bài tập về nhà), nhưng đã xảy ra sự cố.Mẫu có thể & constexpr – nếu không tương thích

template<size_t limit = 3, class result = std::ratio<0, 1>, size_t factorial = 1, size_t count = 1> 
constexpr double e_impl() { 
    if constexpr(limit == 0) { 
     return static_cast<double>(result{}.num)/result{}.den; 
    } 
    return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>(); 
} 

Trong khi giá trị được tính là chính xác, trình biên dịch sẽ phát ra lỗi về tràn trong mẫu. Có vẻ như biến số limit nằm ngoài phạm vi (bên dưới 0), nhưng không nên xảy ra khi số 0 –case đang được xử lý theo tuyên bố if constexpr(…).

Vì vậy, câu hỏi là, tôi có sai và hành vi đó nên được dự kiến ​​hay là lỗi trình biên dịch? Biên dịch với GCC 7.1.0.

Trả lời

6

Để tránh lỗi này, hãy đặt sự trở lại thứ hai rõ ràng vào chi nhánh khác:

template<size_t limit = 3, class result = std::ratio<0, 1>, size_t factorial = 1, size_t count = 1> 
constexpr double e_impl() { 
    if constexpr(limit == 0) { 
     return static_cast<double>(result{}.num)/result{}.den; 
    } 
    else 
    { 
     return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>(); 
    } 
} 

https://godbolt.org/g/PdV7m7

Rational:

Trong một instantiation của hàm kèm theo mẫu hoặc lambda chung , nếu điều kiện được chuyển đổi là đúng và câu lệnh bao gồm một hàm con khác, thì substatement đó không được khởi tạo.

http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0128r1.html

Nó nói gì về một khối khác không bị giới hạn, hoặc một khối mà không phải chạy, vì vậy nó được khởi tạo, ném lỗi. (Lưu ý: cũng không thành công trên clang)

+2

Lý do tại sao câu trả lời này hữu ích hơn. –

+0

@CrazyEddie Nouning adverbs. Làm thế nào rõ ràng. – Yakk

5

Không, đây không phải là lỗi. Vấn đề ở đây là ngay cả khi limit0 và bạn ngăn chặn sự đệ quy trình biên dịch vẫn tem ra

return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>(); 

vì nó là vô điều kiện. Bạn cần phải đặt nó vào một khối khác để có được nó chỉ để biên dịch khi limit không phải là 0.

template<size_t limit = 3, class result = std::ratio<0, 1>, size_t factorial = 1, size_t count = 1> 
constexpr double e_impl() { 
    if constexpr(limit == 0) 
     return static_cast<double>(result{}.num)/result{}.den; 
    else 
     return e_impl<limit - 1, std::ratio_add<result, std::ratio<1, factorial>>, factorial * count, count + 1>(); 
} 
Các vấn đề liên quan