Я экспериментирую с функциями constexpr в С++ 14. Следующий код, который вычисляет факториал, работает как ожидалось:
template <typename T>
constexpr auto fact(T a) {
if(a==1)
return 1;
return a*fact(a-1);
}
int main(void) {
static_assert(fact(3)==6, "fact doesn't work");
}
когда он компилируется следующим образом с помощью clang:
> clang++ --version
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
> clang++ -std=c++14 constexpr.cpp
Однако, когда я изменяю определение fact
для использования тройного оператора ?
:
template <typename T>
constexpr auto fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
Я получаю следующую ошибку компилятора:
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:12:31: fatal error: recursive template instantiation exceeded maximum depth of
256
return a==T(1) ? T(1) : a*fact(a-1);
... snip ...
constexpr.cpp:16:19: note: in instantiation of function template specialization 'fact<int>'
requested here
static_assert(fact(3)==6, "fact doesn't work");
Проблема исправлена, если я явно укажу тип возврата T (вместо того, чтобы использовать auto для вывода возвращаемого типа)
template <typename T>
constexpr T fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
Если я удалю параметр шаблона, шаблон повторяется (тернарная версия терпит неудачу и работает версия if
)
// this works just fine
constexpr auto fact(int a) {
if(a==1)
return 1;
return a*fact(a-1);
}
тогда как это не работает
constexpr auto fact(int a) {
return a==1 ? 1 : a*fact(a-1);
}
со следующей ошибкой
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:16:25: error: function 'fact' with deduced return type cannot be used before it
is defined
return a==1 ? 1 : a*fact(a-1);
^
constexpr.cpp:15:16: note: 'fact' declared here
constexpr auto fact(int a) {
^
constexpr.cpp:20:26: error: invalid operands to binary expression ('void' and 'int')
static_assert(fact(3)==6, "fact doesn't work");
~~~~~~~^ ~
2 errors generated.
Что здесь происходит?