2013-03-27 1 views
1

두 클래스가 있습니다. 하나는 다른 클래스로부터 상속됩니다. 다음 기본 클래스의 관련 부분은 (분명히이 클래스는 특별히 등 ctors하는 dtor, 및 operator[]이 있지만, I는 당면한 문제 무관 이러한 생각)C++ 동적으로 매개 변수의 클래스를 찾아서 캐스팅합니다.

#include <array> 

template < class T, unsigned int N > 
class Vector 
{ 
public: 
    template < class U, unsigned int M > friend Vector< U, M > operator+ (const Vector< U, M >&, const Vector< U, M >&); 

    template < class U, unsigned int M > friend std::ostream& operator<< (std::ostream&, const Vector< U, M >&); 
}; 

상속 클래스 (다시, 분명히 내가 관련이없는 생각하는 부분을 촬영했습니다) :

#include "Vector.h" 

template < class T, unsigned int N > 
class Polynomial 
    : public Vector< T, N > 
{ 
public: 
    template < class U, unsigned int M > friend std::ostream& operator<< (std::ostream&, const Polynomial< U, M >&); 
}; 

(주 : 할 그렇지 않으면 GCC는 "그림자"에 대해 불평 때문에 친구 기능, 클래스보다 템플릿에 대해 서로 다른 문자를 사용합니다. 그러나 논리는 동일합니다.)

Vector는 한 방향으로 인쇄합니다 (예 : < 3, 5, 1 >); Polynomial 다른 것을 인쇄하십시오 (예 : 3 x^2 + 5 x + 1).

그러나 문제가 발생합니다. Polynomial을 두 개 추가하려고하면 컴파일러에서 template < class U, unsigned int M > Vector< U, M > operator+ (const Vector< U, M >&, const Vector< U, M >&)을 사용하고 물론 Vector을 반환합니다. 따라서 std::cout << poly1 + poly2;과 같은 것을 시도하면 결과 디스플레이의 형식이 잘못됩니다.

template < class U, unsigned int M > Vector< U, M > operator+ (const Vector< U, M >&, const Vector< U, M >&)은 해당 매개 변수의 실제 데이터 유형을 감지하고 이에 따라 반환 값을 캐스팅하도록 수정하고자합니다 (예 : Polynomial이 전달되면 Polynomial을 반환). 가능한 경우 operator+Vector의 가능한 모든 하위 클래스에 대해 알고 (가능하면 합법적 인 욕구일까요?) 각 하위 클래스에 대해 새로운 operator+ 함수를 만들지 않고이 작업을 수행하고 싶습니다. 오버로드 된 연산자이며 각 파생 된 클래스에 대해 거의 동일한 코드를 10 번 복사하는 것을 피하기를 원합니다.

나는 이것이 파이썬에서 가능하다는 것을 안다. C++은 그런 것을 지원합니까?

답변

2

결과를 Vector<T,N>으로 계산하면 단순히 (합법적으로) Polynomial<T,N>으로 캐스팅 할 수 없습니다. 원하는 효과를 얻으려면 좀 더 깊은 수정이 필요합니다. 무료 operator+, 원하는 결과 형식을 제공 할 수있는 구현 및 Vector<T,N>에서 파생 된 모든 것을 검색하는 방법이 필요합니다. 그것을 구축합시다. 이를 위해

가) 감지 모든 Vector<T,N>

, 당신은 빈 기본 최적화 (EBO에 의해 멀리 최적화 될 것이다 빈 기본 클래스에서 파생 수)와 그 std::enable_if에 의해 탐지 가능 :

struct VectorBase {}; 

template< class T, unsigned int N > 
class Vector 
{ 
    // ... 
}; 

UVector< T, N >에서 파생 된 클래스이면 std::is_base_of< VectorBase, U >::value으로 확인할 수 있습니다. 절대적으로 정확하려면 VectorBase 자체 (!std::is_same< U, VectorBase >::value)를 제외해야하지만 이는 사용 사례에 필요하지 않을 수 있습니다.

b) 원하는 반환 유형을 전달하는 구현입니다.

template< class T, unsigned int N > 
class Vector 
{ 
    template < class U, unsigned int M > 
    friend Vector< U, M > operator+ (const Vector< U, M >&, const Vector< U, M >&); 
}; 

로 대체해야합니다 : 전에 우리는 그렇게

template< class T, unsigned int N > 
class Vector 
{ 
    friend Vector< T, N > operator+ (const Vector< T, N >&, const Vector< T, N >&); 
}; 

을 일반적인 경우에 대해. 하지만 당신은 그래서 나중에 Polynomial<T,N> 될 수있는 특별한 반환 형식, 필요

template< class T, unsigned int N > 
class Vector 
{ 
public: 
    template< typename R > 
    static R add(const Vector< T, N >& lhs, const Vector< T, N >& rhs) 
    { 
     static_assert(std::is_base_of<VectorBase,R>::value, 
         "R needs to be derived from Vector<T,N>"); 
     R result; 
     // implement it here... 
     return result; 
    } 
}; 

C) add를 호출하는 operator+을 제공하고 그 SFINAE에 의해 보호됩니다 :

// as a free function: 
template< typename V > 
typename std::enable_if< std::is_base_of< VectorBase, V >::value, V >::type 
operator+(const V& lhs, const V& rhs) 
{ 
    return V::template add<V>(lhs, rhs); 
} 

마이너스 몇 가지 작은 오타 (I 테스트하지 않았다면)이 전략이 효과가 있습니다.

+0

답변 해 주셔서 감사합니다. 여기서 익숙하지 않은 코드를보고 있으므로 연구를 해보겠습니다. – Arandur

+0

@Arandur : 나는 그것이 진보 된 것을 인정하지만 나는 쉬운 길을 보지 못했다. 또한이 코드는 C++ 11 기능을 사용하므로이 기능을 지원하는 컴파일러가 필요하며 대개 C++ 11을 명시 적으로 활성화해야합니다. –

+0

음, 그것은 꽤 검은 색 마술이지만, 매력처럼 작동합니다! 당신의 대답에 다시 한번 감사드립니다. – Arandur

관련 문제