2012-08-01 3 views
1

현재 연구를위한 작은 수학 벡터 및 행렬 및 일부 특수 함수를 다루기 위해 라이브러리를 작성하고 있습니다. 현재 CRTP 트릭을 테스트 중입니다. 다음 코드는 마지막 행에서 오류를 생성하고 그 이유를 알 수 없습니다. 이유는 알 수 없습니다 :CRTP 수학 배열 클래스 : 컴파일이 실패합니다.

#include <iostream> 
#include <initializer_list> 
#include <type_traits> 

// Abstract class 
template<class TCRTP, class T, unsigned int TSIZE> class AbstractArray 
{ 
    // Constructor 
    public: 
     inline AbstractArray() : _data{} 
     { 
      std::cout<<"AbstractArray::AbstractArray()"<<std::endl; 
     } 

    // Copy constructor 
    public: 
     template<class TCRTP0, class T0> inline AbstractArray(const AbstractArray<TCRTP0, T0, TSIZE> &rhs) 
     { 
      std::cout<<"AbstractArray::AbstractArray(const AbstractArray<TCRTP0, T0, TSIZE> &rhs)"<<std::endl; 
      for(unsigned int i = 0; i < TSIZE; ++i) { 
       _data[i] = rhs[i]; 
      } 
     } 

    // Initializer list constructor 
    public: 
     template<class T0> inline AbstractArray(const std::initializer_list<T0>& rhs) 
     { 
      std::cout<<"AbstractArray::AbstractArray(const std::initializer_list<T0>& rhs)"<<std::endl; 
      const T0* it = rhs.begin(); 
      for (unsigned int i = 0; i < TSIZE; ++i) { 
       _data[i] = *it; 
       ++it; 
      } 
     } 

    // Destructor 
    public: 
     inline ~AbstractArray() 
     { 
      std::cout<<"AbstractArray::~AbstractArray()"<<std::endl; 
     } 

    // Subscript operator 
    public: 
     inline const T& operator[](const unsigned int i) const 
     { 
      std::cout<<"AbstractArray::operator[](const unsigned int i) const"<<std::endl; 
      return _data[i]; 
     } 
     inline T& operator[](const unsigned int i) 
     { 
      std::cout<<"AbstractArray::operator[](const unsigned int i)"<<std::endl; 
      return _data[i]; 
     } 

    // Assignment operator 
    public: 
     template<class TCRTP0, class T0> inline AbstractArray<TCRTP, T, TSIZE>& operator=(const AbstractArray<TCRTP0, T0, TSIZE>& rhs) 
     { 
      std::cout<<"AbstractArray::operator=(const AbstractArray<TCRTP0, T0, TSIZE>& rhs)"<<std::endl; 
      for (unsigned int i = 0; i < TSIZE; ++i) { 
       _data[i] = rhs[i]; 
      } 
      return *this; 
     } 

    // Sum assignment 
    public: 
     template<class TCRTP0, class T0> inline AbstractArray<TCRTP, T, TSIZE>& operator+=(const AbstractArray<TCRTP0, T0, TSIZE>& rhs) 
     { 
      std::cout<<"AbstractArray::operator+=(const AbstractArray<TCRTP0, T0, TSIZE>& rhs)"<<std::endl; 
      for (unsigned int i = 0; i < TSIZE; ++i) { 
       _data[i] += rhs[i]; 
      } 
      return *this; 
     } 

    // Sum operator 
    public: 
     template<class T0> inline AbstractArray<TCRTP, typename std::common_type<T, T0>::type, TSIZE> operator+(const AbstractArray<TCRTP, T0, TSIZE>& rhs) const 
     { 
      return AbstractArray<TCRTP, typename std::common_type<T, T0>::type, TSIZE>(*this) += rhs; 
     } 

    // Data members 
    protected: 
     T _data[TSIZE]; 
}; 

// Array class 
template<class T, unsigned int TSIZE> class NArray : public AbstractArray<NArray<T, TSIZE>, T, TSIZE> 
{ 
    // Constructor 
    public: 
     inline NArray() : AbstractArray<NArray<T, TSIZE>, T, TSIZE>() 
     { 
      std::cout<<"NArray::NArray()"<<std::endl; 
     } 

    // Copy constructor 
    public: 
     template<class TCRTP0, class T0> inline NArray(const AbstractArray<TCRTP0, T0, TSIZE> &rhs) : AbstractArray<NArray<T, TSIZE>, T, TSIZE>(rhs) 
     { 
      std::cout<<"NArray::NArray(const AbstractArray<TCRTP0, T0, TSIZE> &rhs)"<<std::endl; 
     } 

    // Initializer list constructor 
    public: 
     template<class T0> inline NArray(const std::initializer_list<T0>& rhs) : AbstractArray<NArray<T, TSIZE>, T, TSIZE>(rhs) 
     { 
      std::cout<<"NArray::NArray(const std::initializer_list<T0>& rhs)"<<std::endl; 
     } 

    // Destructor 
    public: 
     inline ~NArray() 
     { 
      std::cout<<"NArray::~NArray()"<<std::endl; 
     } 
}; 

// Vector class 
template<class T, unsigned int TSIZE> class NVector : public AbstractArray<NVector<T, TSIZE>, T, TSIZE> 
{ 
    // Constructor 
    public: 
     inline NVector() : AbstractArray<NVector<T, TSIZE>, T, TSIZE>() 
     { 
      std::cout<<"NVector::NVector()"<<std::endl; 
     } 

    // Copy constructor 
    public: 
     template<class TCRTP0, class T0> inline NVector(const AbstractArray<TCRTP0, T0, TSIZE> &rhs) : AbstractArray<NVector<T, TSIZE>, T, TSIZE>(rhs) 
     { 
      std::cout<<"NVector::NVector(const AbstractArray<TCRTP0, T0, TSIZE> &rhs)"<<std::endl; 
     } 

    // Initializer list constructor 
    public: 
     template<class T0> inline NVector(const std::initializer_list<T0>& rhs) : AbstractArray<NVector<T, TSIZE>, T, TSIZE>(rhs) 
     { 
      std::cout<<"NVector::NVector(const std::initializer_list<T0>& rhs)"<<std::endl; 
     } 

    // Destructor 
    public: 
     inline ~NVector() 
     { 
      std::cout<<"NVector::~NVector()"<<std::endl; 
     } 
}; 

// Main 
int main() 
{ 
    NArray<double, 3> a1({1., 2., 3.}); 
    std::cout<<std::endl; 
    NArray<int, 3> a2({4., 5., 6.}); 
    std::cout<<std::endl; 
    NArray<double, 3> a3({7., 8., 9.}); 
    std::cout<<std::endl; 
    NVector<double, 3> v1({11., 12., 13.}); 
    std::cout<<std::endl; 
    NVector<double, 3> v2({14., 15., 16.}); 
    std::cout<<std::endl; 
    NVector<double, 3> v3({17., 18., 19.}); 
    std::cout<<std::endl; 
    NVector<int, 3> v4({20., 21., 22.}); 
    std::cout<<std::endl; 
    a1 = a2; 
    std::cout<<std::endl; 
    std::cout<<"TEST -> a1 = "<<a1[0]<<" "<<a1[1]<<" "<<a1[2]<<std::endl; 
    std::cout<<std::endl; 
    v1 = a2; 
    std::cout<<std::endl; 
    std::cout<<"TEST -> v1 = "<<v1[0]<<" "<<v1[1]<<" "<<v1[2]<<std::endl; 
    std::cout<<std::endl; 
    v1 += a2; 
    std::cout<<std::endl; 
    std::cout<<"TEST -> v1 = "<<v1[0]<<" "<<v1[1]<<" "<<v1[2]<<std::endl; 
    std::cout<<std::endl; 
    v1 = a3+a3; 
    std::cout<<std::endl; 
    std::cout<<"TEST -> v1 = "<<v1[0]<<" "<<v1[1]<<" "<<v1[2]<<std::endl; 
    std::cout<<std::endl; 
    //v2 = v3+v4; // <- This line does not work : "error : no match for "operator+" in "v3+v4" 
    std::cout<<std::endl; 
    return 0; 
} 

어떻게 해결할 수 있습니까? 그리고 전문가들에게 질문을 던지십시오. 이런 식으로 연산자를 코딩하는 것이 효율적이라고 생각하십니까? 아니면 코드의 품질을 향상시킬 수있는 몇 가지 수정 사항을 염두에 두시겠습니까? CRTP로 현재 구현을 수정하기 전에 모든 조언을 부탁드립니다.

대단히 감사합니다!

답변

1

당신은 이 사용하여 컴파일 메이크업을 수정할 수 있습니다

v2 = v3.operator+<int> (v4); 

대신 내가 명시 적으로 T0int 어떤 컴파일러를 말한

v2 = v3+v4; // <- This line does not work : "error : no match for 

의. 나는 .operator+<int>을 사용하여 이것을했다.

그러나에는 다른 미묘한 문제가있을 수 있습니다. operator+의 정의에서 인수로 const AbstractArray<TCRTP, T0, TSIZE>& rhs이 필요합니다. 이 경우에 T0 == intTSIZE == 3, 이는 양호합니다. 그러나 문제는 TCRTPNVector<int,3> 일 때 여전히 NVector<double,3>으로 정의되어 있습니까?

요약하면 컴파일러에게 템플릿 매개 변수를 명시 적으로 알릴 수 있습니다. 하지만 두 가지 질문이 제기됩니다.

  • 수동으로 유형을 지정하더라도 올바른 유형입니까? 별표 (TCRTP)와 TCRTP0 (operator+=)을 입력해야합니다.
  • (올바른) 유형을 어떻게 자동으로 추정합니까?
+0

기본 클래스 ('NVector'->'AbstractArray') 로의 변환이'operator +'에 대한 템플릿 인자 공제에서 고려되고 있습니까? 나는 그렇게해서는 안된다. – Andrey

+0

좋은 질문 Andrey. 하지만 내 솔루션에 문제가 있다고 생각합니다. –

+0

당신의 "But"는 아주 좋은 지적입니다. "template 인라인 AbstractArray :: type, TSIZE> 연산자 + (const AbstractArray & rhs) const"는 다음과 같이 정의를 변경합니다. 잘! 현재 구현에서 문제가 아닌 (매우 안전하지 않은 것 같은) 것이 있습니까, 아니면 모두 괜찮습니까 (내 라이브러리는 기본적으로 이것에 의존 할 것입니다)? – Vincent

관련 문제