누군가 첫 번째 템플릿 메타 프로그래밍 방식이 무한 루프가되는 이유를 설명해 줄 수 있지만 두 번째 템플릿은 올바르게 실행됩니다.
#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;
}
답변
(N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val
이 라인은 컴파일 타임에 조건이 알려져 있고 브랜치 중 하나가 절대 사용되지 않더라도 commondivs<N,(M-N)>::val
및의 인스턴스를 생성 commondivs<(N-M),M>::val
합니다.
교체 ? :
로 std::conditional_t
이러한 제한이 없습니다있는 :
static const int val = std::conditional_t<N < M, commondivs<N,(M-N)>, commondivs<(N-M),M>>::val;
답변
문제는 조건 연산자의 모든 피연산자가 평가 모두 있도록 할 것입니다 commondivs<N,(M-N)>
및 commondivs<(N-M),M>
인스턴스화과 취득 val
후 재귀 템플릿 인스턴스화에 리드를 GET 평가합니다.
constexpr 을 적용 하고 constexpr
static
멤버 함수 에 넣을 수 있습니다 .
값이
true
이면 statement-false가 삭제되고 (있는 경우), 그렇지 않으면 statement-true가 삭제됩니다.
template<int N, int M>
struct commondivs {
constexpr static int get_val() {
if constexpr (N<M) return commondivs<N,(M-N)>::val; // if true, the else part won't be evaluated
else return commondivs<(N-M),M>::val; // vice versa
}
static const int val = get_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
. 다른 하나는 다음과 같습니다.
template<int N, int M>
struct commondivs {
static constexpr int min = (N < M) ? N : M;
static constexpr int max = (N < M) ? M : N;
static constexpr int val = commondivs<min, max - min>::val;
};
template<int N>
struct commondivs<N, N> {
static constexpr int val = N;
};
답변
다음과 같은 이유로 무한 재귀가 발생합니다.
static const int val = (N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val;
?:
@Eng가 말했듯이,가 아니기 때문에 프로그래밍을 전혀 템플릿하지 않습니다 constexpr
.
@HolyBlackCat의 답변을보고 싶습니다.