2012-12-09 3 views
8

간단한 벡터 클래스를 작성하고 특정 길이의 벡터에서만 사용할 수있는 일부 멤버 함수를 갖고 싶습니다. 예를 들어 3 요소 벡터). 나는 std :: enable_if를 우연히 발견했고, 내가 원하는 것을 할 수있는 것처럼 보이지만 제대로 작동하지 못하는 것 같다.C++ 11 std :: enable_if를 사용하여 vector가 특정 길이 인 경우 멤버 함수 사용 가능

vec.cpp: In instantiation of ‘class Vector<double, 4u>’: 
vec.cpp:46:22: required from here 
vec.cpp:29:59: error: no type named ‘type’ in ‘struct std::enable_if<false, double>’ 

지적 할 수있는 사람이 내가 잘못 가고 있습니다 :

#include <iostream> 
#include <type_traits> 

template<typename T, unsigned int L> 
class Vector 
{ 
    private: 
     T data[L]; 

    public: 
     Vector<T,L>(void) 
     { 
      for(unsigned int i = 0; i < L; i++) 
      { 
       data[i] = 0; 
      } 
     } 

     T operator()(const unsigned int i) const 
     { 
      return data[i]; 
     } 

     T& operator()(const unsigned int i) 
     { 
      return data[i]; 
     } 

     Vector<typename std::enable_if<L==3, T>::type, L> cross(const Vector<T,L>& vec2) const 
     { 
      Vector<T,L> result; 

      result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1); 
      result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2); 
      result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0); 

      return result; 
     } 
}; 

int main(void) 
{ 
    Vector<double,3> v1; 
    Vector<double,3> v2; 
    Vector<double,3> v3; 
    //Vector<double,4> v4; 

    v1(0) = 1; 
    v1(1) = 2; 
    v1(2) = 3; 

    v2(0) = 4; 
    v2(1) = 5; 
    v2(2) = 6; 

    v3 = v1.cross(v2); 

    std::cout << v3(0) << std::endl; 
    std::cout << v3(1) << std::endl; 
    std::cout << v3(2) << std::endl; 

    return 0; 
} 

컴파일 위의 코드와 내가 컴파일에서 다음과 같은 오류가 Vector<double,4> v4의 선언의 주석을 단 경우, 제대로 실행?

+0

가능한 중복 (HTTP (이 여전히 C++ 표준의-위에서 언급 한 두 단락에서 다음) .com/questions/4880922/can-i-use-on-a-member-function) –

+1

당신은 아마도'typename std :: enable_if > :: type'을 쓰고 싶지 않을 것입니다. 'Vector :: type, L>'. –

+1

(당신은 아마도 const'operator()'가'T const &'를 돌려 주길 원할 것입니다. 현재 코드는 클라이언트가'Vector v; 벡터 const & const_v = v; const_v (2) = 42.0; 42의 쓰기는 일시적으로 발생합니다. 사용자가 예상 한대로가 아닙니다.) –

답변

8
template<unsigned LL = L> 
    Vector<typename std::enable_if<LL==3 && L == 3, T>::type, LL> 
    cross(const Vector<T,LL>& vec2) const 
    { 
    Vector<T,L> result; 

    result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1); 
    result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2); 
    result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0); 

    return result; 
    } 

ps. 이것이 왜이 방법으로 효과가 있습니까?

다른 것들 중에서 차례로 발생 클래스 템플릿 Vector, 내재적 실체화 발생 v4 가변 클래스의 멤버 함수의 선언이 암시 인스턴스의 정의 (14.7.1 암시 실체화 [temp.inst] #1). 물론 후자의 인스턴스 생성은 오류를 발생시킵니다.

우리는 대신이 시점 멤버 템플릿 자체가 인스턴스화에서, 같은 조항에 따라, 멤버 템플릿을 할 멤버 함수를 변경하고이 인스턴스처럼, 더 많거나 적게 보인다면 :

template<unsigned LL = 3> 
Vector<typename std::enable_if<LL==3 && 3 == 3, double>::type, LL> 
cross(const Vector<double,LL>& vec2) const; 

이것은 완전히 유효한 템플릿 선언입니다. 우리는이 시점에서 더 이상의 인스턴스화를 수행하지 않습니다.

실제로 우리가 cross을 호출하려고 시도 할 때 이것은 분명히 "(14.7.1 암시 적 인스턴스화 [temp.inst] # 2에 따라"구성원/함수 정의가 필요한 컨텍스트 " , # 3), cross 템플릿 (두 번째 cross 템플릿, 외부 클래스 템플릿 인스턴스화의 결과 인 템플릿)은 암시 적으로 인스턴스화되며 std::enable_if은 작업을 수행 할 수있는 기회가 주어집니다. 참고로 SFINAE 원칙이 적용되는 상황입니다.

PPS. 조금 더 자세하게 말하자면, OP 질문에 직접적으로 연결되어 있지는 않지만, 비슷한 상황을 다루기 위해 멤버를 템플릿으로 선언 할 필요는 없습니다. 인스턴스화 S<int>에,

#include <type_traits> 

template<typename T> 
struct S 
{ 
    T x; 

    T foo() const { return x; } 

    typename std::remove_pointer<T>::type bar() const { return *x; } 
}; 

S<int> x; 
S<int *> y; 

분명히 : 클래스 템플릿의 멤버는, 예를 들어, 특정 인스턴스에 대해 "유효"하지 만, 여전히 클래스 템플릿을 인스턴스화 할 수있는

는 상황이 있습니다 , 형식이 *x 인 경우 x 형식이 int이므로 올바르지 않습니다. 이 프로그램은 정확합니다. 암시 적 인스턴스화 중에 선언문 만 인스턴스화된다는 점이 중요합니다. 위의 경우 인스턴스 S<int>선언int bar() const;을 인스턴스화합니다. 이는 완전히 올바른 선언입니다.물론

, 우리가 나중에처럼 정의를 S<int>::bar를 인스턴스화하려고하면 :

void f() 
{ 
    x.foo(); 
    // x.bar(); // error 
    y.foo(); 
    y.bar(); 
} 

우리가 오류가 발생합니다. // 유래 :

은 [? 내가 부스트 :: 멤버 함수에 \의 _if 수 있도록를 사용할 수]의

+0

감사합니다. 왜 이것이 내가 가지고있는 것과 다른지 이해할 수 없습니다. 개별 멤버 함수가 템플릿 화되어야하기 때문입니까? – rozzy

+0

@ aero117, 인스턴스화 될 때까지 템플릿 기능에 대한 코드가 생성되지 않습니다. 코드에서 컴파일러는 함수를 포함하여 전체 클래스 (템플릿이 인스턴스화 될 때)에 대한 코드를 생성합니다. 그러나 템플릿으로 함수를 만들 때이 함수의 코드는이 템플릿이 인스턴스화 될 때 (예 : 함수를 호출하여) 생성됩니다. – soon

+0

완전한 기능 설명을위한 명성! –