2010-11-28 3 views
6

다음 서명을 사용하여 일반 벡터 템플릿 클래스 (컨테이너가 아닌 기하학적 엔티티)를 작성하고 있습니다 ...특정 조건이 충족 될 때 C++ 템플릿 클래스 메서드의 인스턴스화를 방지하려면 어떻게해야합니까?

 
template< typename T, unsigned N > 
class vector 
{...} 

... 여기서 T는 산술 유형이고 N은 차원입니다. 교차 곱을 연산자^(클래스 정의 내부에 있음)의 오버로드로 정의하고 N == 3 인 경우에만 사용 가능하게하려고합니다.

 
typename boost::lazy_enable_if_c< (N == 3), vector >::type 
inline operator ^(const vector &rhs) const 
{ 
    vector ret; 
    ret(0) = val_[1] * rhs(2) - val_[2] * rhs(1); 
    ret(1) = val_[2] * rhs(0) - val_[0] * rhs(2); 
    ret(2) = val_[0] * rhs(1) - val_[1] * rhs(0); 
    return ret; 
} 

불행히도이 템플릿을 인스턴스화하면 N! = 3 인 경우 연산자 ^가 참조되지 않아도 다음 오류가 발생합니다.

 
error: no type named ‘type’ in ‘struct boost::lazy_enable_if_c < false, flare::math::vector < flare::math::fixed < short int, 8u >, 2u > >’ 

무엇이 잘못 되었나요? 이 경우 boost :: enable_if에 대한 대안이 있습니까?

대단히 감사합니다.

답변

4

오류 메시지의 근위 원인 the docs에 따르면, "lazy_enable_if의 두 번째 인자는 최초의 파라미터 (조건)이 참일 때마다 type라는 하위 유형을 정의하는 클래스 타입이어야한다."이다 여기에 분명히 만족스럽지 않습니다 (vector 유형에 단지 typedef something type;이 포함되지 않은 경우).

여기에 lazy_...이 필요하지 않습니다. 문서에 따르면 두 번째 인수가 정의되지 않았을 때만 필요합니다 (예 : 두 번째 인수가 typename foo<T>::bar이고 모든 유형이 T 인 경우 bar 유형이 정의되지 않은 경우). vector (여기에서 vector<T, N>을 의미 함)은 항상 정의됩니다.

확실하게 lazy_을 없애거나 아무것도하지 않는 특성 클래스 template <typename T> struct nop { typedef T type; };을 만들고 두 번째 인수를 에 nop<vector>으로 바꿉니다. 하지만 내 생각 엔 당신은 이미 전자를 사용해 본 것입니다. :)

이제 나는 그것이 작동하지 않는 이유를 봅니다. 표준 14.7.1/1에 따르면 : 때 N != 3를 실패하는 모든 방법에 대한 선언을 인스턴스화하려고합니다 인스턴스화 할 수있는 클래스를 야기

Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates;

그래서 아무것도. 따라서 함수 템플릿에 대신 전달되는 항상 존재하는 메서드를 사용해야 할 것입니다. 걱정하지 마세요, 어떤 점잖은 컴파일러는 여전히 통해 인라인 할 수있을 것입니다 :

template< typename T, unsigned N > class vector; // Fwd decl. 

template< typename T, unsigned N > 
inline boost::enable_if_c< (N == 3), vector<T, N> >::type 
magic(const vector<T, N>& lhs, const vector<T, N>& rhs) { 
    /* Do the calculation as before... */ 
    return ret; 
} 

template< typename T, unsigned N > 
class vector { 
    ... 
    inline vector operator ^(const vector &rhs) const { 
     return magic(*this, rhs); 
    } 
}; 

이 작동 그들은 등 사실이라고 (또는 주소가 촬영하지 않는 정의 인스턴스화되지 않은 멤버 함수 때문에).

+0

우선, 깊이있는 설명을 해주셔서 감사드립니다.사실, typedef vector 타입을 가지고 있습니다. 내 클래스 정의 내에서, 그러나 나는이 중요한 세부 사항을 언급하는 것을 잊었다. 그래서 GCC가 왜이 에러를 던지고 있는지 이해하지 못했습니다 :: 정의되지 않았습니다. 또한, 나는 enable_if의 lazy_ 버전의 목적을 오해했습니다. 당신의 설명이 나를 이해하는 데 도움이되었습니다. 이것에 비추어 볼 때, 저는 단순히 연산자의 바깥 쪽 버전으로 바뀌 었습니다.^예상대로 작동했습니다. N! = 3 일 때 생성 된 오류 메시지는 조금 이해가되지 않지만이를 처리 할 수 ​​있습니다. 다시 한번 고마워요! – pmjobin

+0

@pmjobin : 환영합니다 :) 예, 템플릿 오류 메시지는 끔찍합니다 ... –

2

귀하의 문제는 "클래스 정의 내에 있습니다"라고 생각합니다. 메서드를 사용하는 대신 함수를 통해 연산자를 오버로드하면 문제가 줄어들 것이라고 생각합니다.

일단 기능으로 전환하면 마법을 부스트하는 것이 아니라 일반 일반화 된 특수화를 사용하는 것이 가능할 수도 있다고 생각하지만, 그에 대해서는 확실하지 않습니다.

관련 문제