Может кто-нибудь объяснить мне, почему первый способ метапрограммирования шаблона идет в бесконечный цикл, а второй работает правильно.
#include <iostream>
using namespace std;
template<int N, int M>
struct commondivs {
static const int val = (N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val;
};
template<int N>
struct commondivs<N,N> {
static const int val = N;
};
int commondiv(int N, int M){
if(N==M){
return N;
}
return (N<M)?commondiv(N,(M-N)):commondiv((N-M),M);
}
int main() {
cout << commondivs<9,6>::val << endl;
cout << commondiv(9,6) << endl;
return 0;
}
constexpr
это не вариант.constexpr
это не вариант. (Это было введено в C ++ 11). Это делает недействительными существующие ответы. Exxul, пожалуйста, уточните, какой версией C ++ вы ограничены.Ответы:
Эта строка вызывает создание экземпляров обоих
commondivs<N,(M-N)>::val
иcommondivs<(N-M),M>::val
даже если условие известно во время компиляции и одна из ветвей никогда не будет взята.Замените
? :
наstd::conditional_t
, который не имеет этого ограничения:источник
Проблема в том, что все операнды условного оператора будут оцениваться, поэтому оба
commondivs<N,(M-N)>
иcommondivs<(N-M),M>
получить экземпляр и ихval
получить оценку , а затем приводит к рекурсивной шаблона конкретизации.Вы можете применить constexpr, если и поместить его в функцию-
constexpr
static
член.ЖИТЬ
источник
::val
должно быть обязательно сгенерировано в обеих ветвях, но это все еще экземпляр (для шаблона со статическим константным членом). Оценка во время выполнения не происходит ... ну, она, очевидно, не может, так как никогда не компилируется ...Тернарный оператор не похож
if constexpr
: когда компилятор видит его, он должен генерировать код для обеих ветвей. Другими словами, чтобы создать экземпляр шаблонаcommondivs<M, N>
, компилятор создает оба шаблона.commondivs<N, M - N>
иcommondivs<N - M, M>
.В отличие от этого
commondiv(N, M - N)
иcommondiv(N - M, M)
переводятся в два вызова функций. Какой из них взят, будет решено, когда функция будет фактически вызвана.Дополнение.
HolyBlackCat дал решение с
std::conditional_t
. Вот еще один:источник
Вы получаете бесконечную рекурсию, потому что:
не программирование метатемплей вообще, потому что
?:
, как говорит @Eng, неconstexpr
.Вы хотите посмотреть на ответ @ HolyBlackCat.
источник
?:
неconstexpr
.