Напомним вопрос: у вас есть две функции, которые принимают параметр типа T
.Один принимает его параметр как параметр шаблона, а другой - как «нормальный» параметр.Я собираюсь вызвать две функции funcT
и funcN
вместо tfunc
и func
.Вы хотите иметь возможность звонить funcT
с funcN
.Маркировка последнего как constexpr
не помогает.
Любая функция, помеченная как constexpr
, должна быть компилируемой, как если бы constexpr
там не было.constexpr
функции немного шизофреничны.Они переходят к полному константному выражению только при определенных обстоятельствах.
Невозможно реализовать funcN для запуска во время выполнения простым способом, так как он должен был бы работать для all возможные значения t .Это потребует от компилятора создания множества экземпляров tfunc
, по одному для каждого значения t.Но вы можете обойти это, если хотите жить с небольшим подмножеством T. В g ++ существует предел рекурсии шаблона 1024, поэтому вы можете легко обработать 1024 значения T с помощью этого кода:
#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;
}
Используется функция worker
, которая будет рекурсивно преобразовывать «обычный» параметр t
в параметр шаблона u
, который затем используется для создания и выполнения tfunc<T,u>
.
.критическая строка - return funcT<T,u>() : worker<T, u+1>(t-1);
Это имеет ограничения.Если вы хотите использовать long
или другие целочисленные типы, вам придется добавить другую специализацию.Очевидно, этот код работает только для t между 0 и 1000 - точный верхний предел, вероятно, зависит от компилятора.Другой вариант может заключаться в использовании своего рода двоичного поиска с различной рабочей функцией для каждой степени 2:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
Я думаю, что это будет работать вокруг шаблона-рекурсии-лимита, но все равно потребуеточень большое количество экземпляров, что сделает компиляцию очень медленной, если она вообще работает.