Riassociare la domanda: si hanno due funzioni che prendono un parametro di tipo T
. Uno prende il suo parametro come parametro template e l'altro come parametro 'normale'. Ho intenzione di chiamare le due funzioni funcT
e funcN
anziché tfunc
e func
. Si desidera essere in grado di chiamare funcT
da funcN
. Contrassegnare quest'ultimo come constexpr
non aiuta.
Qualsiasi funzione contrassegnata come constexpr
deve essere compilabile come se lo constexpr
non fosse presente. Le funzioni constexpr
sono un po 'schizofreniche. Si diplomano in espressioni costanti in determinate circostanze.
Non sarebbe possibile attuare funcN per funzionare a tempo di esecuzione in modo semplice, come sarebbe bisogno di essere in grado di funzionare per tutte possibili valori di t . Ciò richiederebbe al compilatore di istanziare molte istanze di tfunc
, una per ogni valore di t. Ma puoi ovviare a questo se sei disposto a vivere con un piccolo sottoinsieme di T.C'è un limite modello-ricorsione di 1024 in g ++, in modo da poter facilmente gestire 1024 valori di T con questo codice:
#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;
}
Si utilizza una funzione worker
che ricorsivamente convertire il 'normale' parametro t
in un modello parametro u
, che viene quindi utilizzato per istanziare ed eseguire tfunc<T,u>
.
La linea cruciale è return funcT<T,u>() : worker<T, u+1>(t-1);
Questo ha limitazioni. Se si desidera utilizzare long
o altri tipi integrali, è necessario aggiungere un'altra specializzazione. Ovviamente, questo codice funziona solo per t tra 0 e 1000 - il limite superiore esatto è probabilmente dipendente dal compilatore. Un'altra opzione potrebbe essere quella di utilizzare una ricerca binaria di sorta, con una funzione di operatore diverso per ogni potenza di 2:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
Penso che questo sarà aggirare il modello-ricorsione limite, ma sarà ancora bisogno di molto gran numero di istanziazioni e renderebbe la compilazione molto lenta, se funziona a tutti.
FWIW, Clang 3.1 HEAD genera anche gli stessi errori. – Xeo