Podsumowanie pytania: Masz dwie funkcje, które przyjmują parametr typu T
. Jeden bierze swój parametr jako parametr szablonu, a drugi jako "normalny" parametr. Mam zamiar wywołać dwie funkcje: funcT
i funcN
zamiast tfunc
i func
. Chcesz mieć możliwość dzwonienia pod numer funcT
z funcN
. Oznaczenie tego ostatniego jako constexpr
nie pomaga.
Każda funkcja oznaczona jako constexpr
musi być kompilowana tak, jakby nie było tam constexpr
. constexpr
funkcje są trochę schizofreniczne. W pewnych okolicznościach kończą tylko pełne wyrażenia stałe.
To nie byłoby możliwe do wdrożenia funcN do uruchomienia przy starcie w prosty sposób, jak byłoby to potrzebne, aby móc pracować dla wszystkich możliwych wartości t. Wymagałoby to kompilatora do utworzenia instancji wielu instancji tfunc
, po jednej dla każdej wartości t. Ale możesz obejść to, jeśli chcesz żyć z małym podzbiorem T.Jest to szablon-rekurencji limit 1024 w g ++, dzięki czemu można z łatwością obsługiwać 1024 wartości T z tym kodem:
#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;
}
Wykorzystuje funkcję worker
która rekurencyjnie konwersji „normalnego” parametr t
do szablonu parametr u
, który następnie wykorzystuje do utworzenia instancji i wykonania tfunc<T,u>
.
Kluczowa linia jest return funcT<T,u>() : worker<T, u+1>(t-1);
ta ma swoje ograniczenia. Jeśli chcesz używać long
lub innych typów integralnych, musisz dodać kolejną specjalizację. Oczywiście ten kod działa tylko dla t od 0 do 1000 - dokładny górny limit jest prawdopodobnie zależny od kompilatora. Innym rozwiązaniem może być użycie binarnego wyszukiwania sortuje, z inną funkcją pracownika dla każdej mocy 2:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
myślę, że to będzie działać na całym szablonie rekurencji terminu, ale to nadal wymaga bardzo duża liczba instancji i spowolniłaby kompilację, gdyby w ogóle działała.
FWIW, Clang 3.1 HEAD również wypluwa te same błędy. – Xeo