템플릿 메타 프로그래밍


38

누군가 첫 번째 템플릿 메타 프로그래밍 방식이 무한 루프가되는 이유를 설명해 줄 수 있지만 두 번째 템플릿은 올바르게 실행됩니다.

#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;
}


2
목표는 템플릿 메타 프로그래밍을 사용하는 것이 었습니다. constexpr옵션이 아닙니다.
Exxul

constexpr옵션이 아닌 것을 명시 적으로 만들기 위해 c ++ 98 태그를 추가했습니다 . (C ++ 11에서 소개되었습니다). 기존 답변이 무효화됩니다. Exxul, 어떤 C ++ 버전으로 제한되어 있는지 명확히하십시오.
MSalters

태그를 제거하여 죄송합니다.
Exxul

답변:


44
(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;

15

문제는 조건 연산자의 모든 피연산자가 평가 모두 있도록 할 것입니다 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();
};

라이브


평가 또는 인스턴스화?
Daniel McLaury

@DanielMcLaury 평가; 단순히 인스턴스화되지 않았습니다.
songyuanyao

의 값은 ::val반드시 두 가지 모두에서 생성되어야하지만, 여전히 정적 인스턴스 멤버를 가진 템플릿의 인스턴스화입니다. 런타임에 평가가 발생 하지 않습니다 ... 글쎄, 컴파일되지 않았기 때문에 분명히 불가능합니다 ...
쓸모없는

8

삼항 연산자는 다릅니다 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;
};

0

다음과 같은 이유로 무한 재귀가 발생합니다.

static const int val = (N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val;

?:@Eng가 말했듯이,가 아니기 때문에 프로그래밍을 전혀 템플릿하지 않습니다 constexpr.

@HolyBlackCat의 답변을보고 싶습니다.


1
도움이되지 않습니다. ?:아닙니다 constexpr.
Evg

아뇨. 같은 무한 루프.
Exxul
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.