2010-07-20 7 views
0

ublas에서 사용되는 패턴을 이해하려고합니다. 패턴은 다음과 같습니다C++ 상속 패턴 + CRTP

struct vector : vector_expression<vector> 

곳 vector_expression이 같다 :

template<class E> 
class vector_expression { 
... 
// no constructor or E pointer/reference in class 
// 
const E &operator()() const { 
     return *static_cast<const E*>(this); 
} 

완전한 소스 코드는 여기에 있습니다 : http://www.tena-sda.org/doc/5.2.2/boost/dd/d44/vector__expression_8hpp-source.html#l00088

제 질문은, *static_cast<const E*>(this) 작업을 수행하는 방법? 상속에 의지합니까?

다음 질문 : 나는

template<class E> 
class vector_expression2 : private vector_expression<E> 
{ 
    //friend class ublas::vector_expression<E>; // this is the fix 
    typedef vector_expression<E> base; 
    const E& operator()() const { return base::operator()(); } 
}; 

을 유도 경우 내가 정적 캐스트에 액세스 할 수 vector_expression 기지에 대한 컴파일러 오류가 발생합니다. 왜 그렇게됩니까?

고맙습니다.

+0

죄송합니다. 원래 게시글을 엉망으로 만들고 설명을 변경했습니다. – Anycorn

답변

2

이 기능 템플릿을 제한 할 수있는 트릭 - 종류의 클래스를 제한 할 수 있습니다. 이 벡터 표현, 스칼라 표현, 행렬 표현 등과 같은 개념을 많이 사용하면

template<typename V, typename S> 
some_type operator*(V v, S s); // vector * scalar 

template<typename V, typename S> 
some_type operator*(S s, V v); // scalar * vector 

를 작성하려고 할 수는 스칼라와 벡터를 곱하는 함수 템플릿을 작성하려면하지만이 작동하지 않을 왜냐하면 두 선언 모두 본질적으로 동등하고 아무도 V가 벡터 표현이고 S는 스칼라 표현이라고 가정하지 않기 때문입니다. 그래서, 무엇 uBlas 개발자가 한 일은 이러한 템플릿을 제한하는 CRTP을 사용하는 것입니다

template<typename V, typename S> 
some_Type operator*(vector_expression<V> ve, scalar_expression<S> se); 

는 S가 scalar_expression<S>에서 파생하는 모든 스칼라 표현과 모든 벡터 식 (V)가 vector_expression<V>에서 파생해야이 작업을하려면. 이 연산자는 첫 번째 피연산자가 실제로 벡터의 표현식이고 두 번째 인수가 실제로 스칼라 표현식 인 경우에만 고려됩니다. 이 함수 템플릿을 두 번째 매개 변수로 오버로드하여 두 매개 변수를 모두 바꿀 수 있으며 모든 것이 괜찮습니다.

이제 V와 S (파생 된 유형)에서 액세스 할 수 있으려면 기본 클래스에서 파생 클래스로 캐스트가 필요합니다. 이것이 기본 클래스의 변환 연산자입니다.기본 클래스는 파생 클래스 (템플릿 매개 변수 임)를 알고 있으므로 문제가되지 않습니다. 이 캐스트가 오류를 피할 수있게 해주는 가장 약한 캐스트 연산자를 선택하는 것이 좋습니다. 이것은 static_cast입니다. 상당한 오버 헤드없이 base *를 derived *로 변환하는 데 사용할 수 있습니다.

난 당신이 템플릿으로 자신의 벡터 식을 작성하려면

template<class E> 
class vector_expression2 : private vector_expression<E>; 

이 같은 그것을 할 것이다 당신의 코드를 수행하려고 이해하지 않습니다

template<class E> 
class my_parameterized_vector_expression 
: public vector_expression<my_parameterized_vector_expression<E> >; 

나는 그것이 개인적인 상속과 함께 작동한다고 생각하지 않는다. 최소한 벡터 표현식을 인수로 취하는 모든 함수 템플리트는 여기에서 개인 상속을 사용하는 경우 기본 클래스에서 변환 연산자에 액세스 할 수 없습니다.

+0

. 나는 cublas를위한 브릿지를 만들고 있는데, 나는 프레임 워크를 재사용하면서 동시에 ublas 표현식으로의 변환을 막아야한다. 그래서 나는 액세스를 제어하기 위해 상속을 사용합니다. – Anycorn

1

당신이 말하는 접근 기능 오류는 의미가 없습니다. vector_expressionstruct이고 함수 호출 operator()은 공개입니다. 아마도 vector_expression2::operator()을 호출하려하셨습니까? 그 연산자를 개인용으로 정의 했으므로 오류가 발생했습니다.

문제의 해결책은 생각보다 간단 할 수도 있습니다.

template<class M> 
class matrix_row: public vector_expression<matrix_row<M> > { 
}; 

이것이 의미하는 것은 템플릿 매개 변수가 vector_expression에서 파생 때문에 vector_expression 자체에 템플릿 매개 변수를 캐스팅 할 수 있다는 것입니다 : 당신이 ublas 소스 코드를 보면 당신은 vector_expression을 부여받은 클래스 템플릿 인수로 자신을 전달할 것을 볼 것이다 따라서 *static_cast<const E*>(this)이 작동합니다. 이는 단지 *((const E*)this)이라고 할 수 있습니다.

vector_expression2 클래스과 같이 다시 작성하십시오 :

template<class E> 
class vector_expression2 : public vector_expression<vector_expression2<E>> 
{ 
}; 
+0

이렇게 ... 이것은 템플릿을 사용하여 구현 한 매우 간단한 동적 캐스트와 비슷합니다. 이 패턴의 이름은 무엇입니까? – Anycorn

+1

파생 클래스를 템플릿 매개 변수로 사용하는 클래스에서 파생 된 전체 동작은 CRTP - Curiously Recurring Template Pattern입니다. 이 특별한 연산자는 파생 된 타입으로 컴파일 다운 캐스팅이라고 생각할 수 있습니다. 그렇지 않으면 RTTI로'dynamic_cast'가 필요할 것입니다. 덕분에 –