Thu hồi câu hỏi: Bạn có hai hàm lấy tham số loại T
. Một tham số của nó là tham số mẫu và tham số kia dưới dạng tham số 'bình thường'. Tôi sẽ gọi hai chức năng funcT
và funcN
thay vì tfunc
và func
. Bạn muốn có thể gọi funcT
từ funcN
. Đánh dấu phần sau là constexpr
không giúp ích gì.
Bất kỳ chức năng nào được đánh dấu là constexpr
phải được đồng bộ hóa như thể constexpr
không có ở đó. constexpr
chức năng là một chút tâm thần phân liệt. Họ chỉ tốt nghiệp với các biểu thức liên tục đầy đủ trong một số trường hợp nhất định.
Nó sẽ không thể thực hiện funcN để chạy trong thời gian chạy một cách đơn giản, vì nó sẽ cần để có thể làm việc cho tất cả giá trị có thể của t. Điều này sẽ yêu cầu trình biên dịch để khởi tạo nhiều trường hợp của tfunc
, một cho mỗi giá trị của t. Nhưng bạn có thể giải quyết vấn đề này nếu bạn sẵn sàng sống với một nhóm nhỏ T.Có một giới hạn mẫu-đệ quy 1024 trong g ++, vì vậy bạn có thể dễ dàng xử lý 1024 giá trị của T với mã này:
#include<iostream>
#include<functional>
#include<array>
using namespace std;
template <typename T, T t>
constexpr T funcT() {
return t + 10;
}
template<typename T, T u>
constexpr T worker (T t) {
return t==0 ? funcT<T,u>() : worker<T, u+1>(t-1);
}
template<>
constexpr int worker<int,1000> (int) {
return -1;
}
template <typename T>
constexpr T funcN(T t)
{
return t<1000 ? worker<T,0>(t) : -1;
}
int main()
{
std::cout << funcN(10) << std::endl;
array<int, funcN(10)> a; // to verify that funcN(10) returns a constant-expression
return 0;
}
Nó sử dụng một hàm worker
mà đệ quy sẽ chuyển đổi 'bình thường' tham số t
thành một mẫu tham số u
, sau đó nó sử dụng để khởi tạo và thực hiện tfunc<T,u>
.
Dòng quan trọng là return funcT<T,u>() : worker<T, u+1>(t-1);
Điều này có giới hạn. Nếu bạn muốn sử dụng long
hoặc các loại tích phân khác, bạn sẽ phải thêm một chuyên môn khác. Rõ ràng, mã này chỉ hoạt động cho t từ 0 đến 1000 - giới hạn trên chính xác có thể phụ thuộc vào trình biên dịch. Một lựa chọn khác có thể được sử dụng tìm kiếm nhị phân của các loại, với một chức năng lao động khác nhau cho mỗi sức mạnh của 2:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
Tôi nghĩ rằng điều này sẽ làm việc xung quanh hạn template-đệ quy, nhưng nó vẫn sẽ đòi hỏi rất số lượng lớn các cảnh báo và sẽ làm cho biên dịch rất chậm, nếu nó hoạt động.
FWIW, Clang 3.1 HEAD cũng phun ra các lỗi tương tự. – Xeo