Поскольку constexpr должен гарантировать, что функция содержит только компиляцию
постоянные времени, и оценивается во время компиляции (по крайней мере, вот что
я думаю, что это так), я подумал, что это может быть решением этой проблемы.
Функция constexpr
может использоваться в контексте константного выражения, но не ограничивается одним. В этом отношении они отличаются от метафункции и регулярной функции. Рассмотрим проблему возврата наследника целого числа:
// Regular function
int f(int i)
{ return i + 1; }
// Regular metafunction
template<int I>
struct g {
static constexpr auto value = I + 1;
};
// constexpr function
constexpr int h(int i)
{ return i + 1; }
// Then...
{
// runtime context: the metafunction can't be used
int i;
std::cin >> i;
f(i); // Okay
g<i>::value; // Invalid
h(i); // Okay
// compile time context: the regular function can't be used
char a[f(42)]; // Invalid
char b[g<42>::value]; // Okay
char c[h(42)]; // Okay
}
constexpr
имеет другие применения (например, конструкторы), но когда дело доходит до constexpr
функций, это суть этого: некоторые функции должны быть доступны как во время выполнения, так и в постоянном контексте, потому что некоторые вычисления доступны в обоих. Можно вычислить i + 1
, является ли i
константой времени компиляции или извлечено из std::cin
.
Это означает, что внутри тела функции constexpr
параметры не сами являются константными выражениями. Так что то, что вы пытаетесь, невозможно. Ваша функция не может справиться с
int i;
std::cin >> i;
get_f(i); // what's the return type?
и нарушение происходит здесь:
constexpr auto get_f(T t)
-> decltype( &f<T,t> ) // <-
Поскольку t
не является константным выражением в соответствии с правилами языка (несмотря ни на что, даже если вы на самом деле передаете только константные выражения в), оно не может отображаться как второй шаблон параметр f
.
(А на более широком рисунке это означает, что нет, вы не можете использовать вычитание аргументов из шаблонов function для удобной передачи не типового параметра в шаблон class .)