Alguém pode me explicar por que o primeiro método de meta-programação de modelos está indo para um loop infinito, mas o segundo é executado corretamente.
#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
não é uma opção.constexpr
não é uma opção. (Foi introduzido no C ++ 11). Isso invalida as respostas existentes. Exxul, esclareça a qual versão do C ++ você está limitado.Respostas:
Essa linha causa instanciação de ambos
commondivs<N,(M-N)>::val
ecommondivs<(N-M),M>::val
, mesmo que a condição seja conhecida no momento da compilação e uma das ramificações nunca será executada.Substitua
? :
porstd::conditional_t
, que não possui esta limitação:fonte
O problema é todos os operandos do operador condicional será avaliado, então ambos
commondivs<N,(M-N)>
ecommondivs<(N-M),M>
se instanciado e seuval
get avaliadas e, em seguida, leva a instanciação de modelo recursivo.Você pode aplicar constexpr if e colocá-lo em uma
constexpr
static
função de membro.VIVER
fonte
::val
deve ser gerado nos dois ramos, com certeza, mas isso ainda é instanciação (de um modelo com um membro const estático). A avaliação em tempo de execução não acontece ... bem, obviamente, não pode, pois nunca compila ... #O operador ternário não é como
if constexpr
: quando um compilador o vê, ele precisa gerar código para os dois ramos. Em outras palavras, para instanciar um modelocommondivs<M, N>
, um compilador instancia os modeloscommondivs<N, M - N>
ecommondivs<N - M, M>
.Em contraste com isso,
commondiv(N, M - N)
ecommondiv(N - M, M)
são traduzidos em duas chamadas de função. Qual deles é escolhido, será decidido quando a função for realmente chamada.Adição.
HolyBlackCat deu uma solução com
std::conditional_t
. Aqui está outro:fonte
Você obtém recursão infinita porque:
não é programação de metatemplate
?:
, porque , como diz o @Eng, não éconstexpr
.Você quer ver a resposta de @ HolyBlackCat.
fonte
?:
não éconstexpr
.