2012-08-11 4 views
8

Scott Meyers의 "Effective C++"항목 48에 대한 빠른 질문이 있습니다. 내가 템플릿 프로그래밍에 열거를 사용해야합니까 왜 난 그냥C++의 템플릿, 열거 형을 사용해야하는 이유

#include <iostream> 
    using namespace std; 

    template <unsigned n> 
    struct Factorial 
    { 
     enum { value=n*Factorial<n-1>::value }; 
    }; 

    template <> 
    struct Factorial<0> 
    { 
     enum { value=1}; 
    }; 

    int main() 
    { 
     cout<<Factorial<5>::value<<endl; 
     cout<<Factorial<10>::value<<endl; 
    } 

을 아래 책에서 복사 한 코드를 이해하지? 다른 방법이 있나요? 미리 도움을 주셔서 감사합니다.

답변

8

당신은 static const int도 사용할 수 있습니다

template <unsigned n> 
struct Factorial 
{ 
    static const int value= n * Factorial<n-1>::value; 
}; 

template <> 
struct Factorial<0> 
{ 
    static const int value= 1; 
}; 

이도 잘해야한다. 두 경우 모두 결과가 동일합니다.

아니면 기존 클래스 템플릿을 사용할 수 있습니다, 같은 std::integral_constant로 (C++ 11 만)과 같이 나와 즈가 말한대로

template <unsigned n> 
struct Factorial : std::integral_constant<int,n * Factorial<n-1>::value> {}; 

template <> 
struct Factorial<0> : std::integral_constant<int,1> {}; 
+0

실제로이 질문에 답하지 않고 'enum'을 사용했습니다. – Puppy

+0

@Nawaz는 분명히 답을 알고 있지만 명확히 진술하지는 않았습니다. 일부 컴파일러에서'static const int'는 컴파일 타임 상수 인 ** 보증되지 않습니다. 왜냐하면 pre-C++ 11 표준은 컴파일러가이를 해결하기 위해 철저한 시도를하지 않기 때문입니다. 따라서,'Factorial '에서와 같이 ** 템플릿 인자로'value'를 사용하려고하면 컴파일러가'value'의 인스턴스를 constexpr으로 만들지 않기로 결정했기 때문에 실패 할 것입니다. – rwong

1

당신은 static const int를 사용할 수 있습니다. Scott Myers가 enum을 사용하는 이유는 정적 const 정수의 클래스 초기화에서 컴파일러 지원이 책을 썼을 때 조금 제한되었다고 생각하기 때문입니다. 따라서 열거 형은 더 안전한 선택이었습니다.

2

보다 구체적으로 static const int을 사용하여 올바른 방법으로 많은 컴파일러에서 지원되지 않았기 때문에 "열거 형 해킹"이 존재합니다. 현대 컴파일러에서는 중복 적입니다.

4

다른 답변은 대체 방법을 잘 다루고 있지만 아무도 enum (또는 static const int)이 필요한 이유를 설명하지 못했습니다.

#include <iostream> 

int Factorial(int n) 
{ 
    if (n == 0) 
     return 1; 
    else 
     return n * Factorial(n-1); 
} 

int main() 
{ 
    std::cout << Factorial(5) << std::endl; 
    std::cout << Factorial(10) << std::endl; 
} 

쉽게 이해 할 수 있어야한다 :

먼저 다음 템플릿이 아닌 동등한를 고려한다. 그러나 계승 값이 런타임에 계산된다는 단점이 있습니다. 즉, 프로그램을 실행 한 후 컴파일러가 순환 함수 호출 및 계산을 실행합니다.

템플릿 접근법은 컴파일시 동일한 계산을 수행하고 그 결과를 결과 실행 파일에 저장하는 것입니다. 즉, 예를 들어 당신이 모두 뭔가 결의를 발표 :

int main() 
{ 
    std::cout << 120 << std::endl; 
    std::cout << 3628800 << std::endl; 
} 

그러나 그것을 달성하기 위해, 당신은 '트릭'은 계산을 수행에 컴파일러에 있습니다. 그렇게하기 위해서는 결과를 어딘가에 저장해야합니다.

enum 정확히 그렇게하기 위해 있습니다. 나는 이 작동하지 않을 것이라고 지적함으로써 그곳에을 설명하려고 노력할 것입니다.

int 정규식을 사용하려고 시도하면 int과 같은 비 정적 멤버는 인스턴스화 된 개체에서만 의미가 있기 때문에 작동하지 않습니다. 그리고 이렇게 값을 할당 할 수는 없지만 대신 생성자에서 값을 할당 할 수 있습니다. 일반 int은 작동하지 않습니다.

대신 인스턴스가 생성되지 않은 클래스에서 액세스 할 수있는 무언가가 필요합니다. 시도해 볼 수 있습니다 static int하지만 여전히 작동하지 않습니다.실제로 아웃 오브 라인, 코드가 컴파일하지만 두 0의 발생합니다 그 정의를 넣으면

c.cxx:6:14: error: non-const static data member must be initialized out of line 
       static int value=n*Factorial<n-1>::value ; 
         ^ ~~~~~~~~~~~~~~~~~~~~~~~ 

: clang 당신에게 문제의 매우 간단한 설명을 제공합니다. 이 형식은 값의 계산을 프로그램 초기화로 지연시키고 올바른 순서를 보장하지 않기 때문입니다. 계산되기 전에 Factorial<n-1>::value 초가 획득되어 0이 반환되었을 가능성이 높습니다. 또한, 그것은 여전히 ​​우리가 실제로 원하는 것이 아닙니다.

마지막으로 static const int을 입력하면 예상대로 작동합니다. 컴파일 시간에 static const을 계산해야하기 때문에 그게 바로 우리가 원하는 것입니다. 이제 다시 코드를 입력하자 : 당신이 Factorial<5>의 인스턴스를

#include <iostream> 

template <unsigned n> 
struct Factorial 
{ 
    static const int value=n*Factorial<n-1>::value ; 
}; 

template <> 
struct Factorial<0> 
{ 
    static const int value=1; 
}; 

int main() 
{ 
    std::cout << Factorial<5>::value << std::endl; 
    std::cout << Factorial<10>::value << std::endl; 
} 

우선; static const int 컴파일러가 컴파일 타임에 해당 값을 계산해야합니다. 실제로 다른 값을 계산해야하는 경우 Factorial<4> 유형을 인스턴스화합니다. 그리고이 값은 Factorial<0>에 도달 할 때까지 계속됩니다.이 값은 더 많은 인스턴스를 생성하지 않고 계산할 수 있습니다.

그래서, 그것은 대체 방법과 설명이었습니다. 코드를 이해하는 데 최소한 도움이 되었기를 바랍니다.

내가 처음에 게시 한 재귀 함수 대신이 템플릿을 사용할 수 있습니다. 당신은 대체 : 전문화 struct Factorial<0>

static const int value = ...
  • return x;, t<x-1>::value
  • f(x-1),
  • if (n == 0).

그리고 이미 지적 된 바와 같이 enum 자체에 대한,이 static const int 같은 동작을 시행 할 예에서 사용 된. 모든 enum 값을 컴파일 할 때 알 필요가 있으므로 컴파일시에 모든 요청 된 값을 계산해야하기 때문에 이와 같습니다.

관련 문제