2012-01-06 3 views
0

私はいくつかの特殊化されたベクトルテンプレートを書いているので、ベクトルの最初のいくつかの項目(x、y、z、wなど)サイズ。 KennyTM's answerはこれに大きな助けとなりました。また、演算子を自然に使用できるように、Curiously recurring template patternの形式を追加しました。ここでは、基本クラスと追加機能(簡潔にするために省略最もメンバーの実装)との専門である:CRTPとテンプレートの特殊化を伴う演算子の奇妙な振る舞い

template<int Dim, typename V, typename ItemType = float> 
class VectorImpl 
{ 
public: 
    typedef ItemType value_type;  
    VectorImpl() { elements.fill(0); }  
    VectorImpl(std::initializer_list<ItemType> init_list); 

     V operator+(const V& other) 
    { 
     V result; 
     for (int i = 0; i < Dim; ++i) 
      result.elements[i] = elements[i] + other.elements[i]; 

     return result; 
    } 

    QString toString();  
     // ... other members ... 

protected: 
    VectorImpl(const VectorImpl& other) = default; 

protected: 
    std::array<ItemType, Dim> elements; 
}; 

template<int Dim, typename ItemType = float> 
class Vector : public VectorImpl<Dim, Vector<Dim, ItemType>, ItemType> 
{ 
    typedef VectorImpl<Dim, Vector<Dim, ItemType>, ItemType> ParentType; 
public: 
    Vector() : ParentType() {} 
    Vector(const ParentType& other) : ParentType(other) {} 
    Vector(std::initializer_list<ItemType> init_list) : ParentType(init_list) {} 
}; 

template<typename ItemType> 
class Vector<3, ItemType> : public VectorImpl<3, Vector<3, ItemType>, ItemType> 
{ 
    typedef VectorImpl<3, Vector<3, ItemType>, ItemType> ParentType; 
public: 
    Vector() : ParentType() {} 
    Vector(const ParentType& other) : ParentType(other) {} 
    Vector(std::initializer_list<ItemType> init_list) : ParentType(init_list) {} 
    ItemType x() const { return this->elements[0]; } 
    ItemType y() const { return this->elements[1]; } 
    ItemType z() const { return this->elements[2]; } 
}; 

は、と私はqDebug()<<サポートを追加したかったので、私はこれをしなかった:

template<int Dim, typename ItemType> 
QDebug operator<<(QDebug dbg, Vector<Dim, ItemType>& v) 
{ 
    dbg.nospace() << v.toString(); 
    return dbg.space(); 
} 

、コードは、次のことはコンパイルし、動作します:

Vector<3> v1 = { 3,4,5 }; 
qDebug() << v1; 

この1は、あまりにも、ありません:

Vector<3> v1 = { 3,4,5 }; 
Vector<3> v2 = { 1,-1,1 }; 
qDebug() << v1; 
auto v3 = v1 + v2; 
qDebug() << v3; 

しかし、この1つはない:

Vector<3> v1 = { 3,4,5 }; 
Vector<3> v2 = { 1,-1,1 }; 
qDebug() << (v1 + v2); 

コンパイラは言う:

error: no match for 'operator<<' in 'qDebug()() << v1.Vector<3>::.VectorImpl::operator+ [with int Dim = 3, V = Vector<3>, ItemType = float]((*(const Vector<3>*)(& v2)))'

何が起こっていますか?変数に代入するときに、v1 + v2の型が異なるのはなぜですか?これをコンパイルするにはどうすればよいですか?

答えて

4

出力機能にのconst参照を与える、または(例えば、あなたの加算結果である一時的など)右辺値がそれに結合しない(ともそのことについては、実際の定数は、意志):

は、
QDebug operator<<(QDebug dbg, Vector<Dim, ItemType> const & v) 
//             ^^^^^ 

またconstのようtoStringを宣言します

QString toString() const; 
//     ^^^^^ 
+0

私はこの問題のように感じる(参照のconstをしていない)SOにたくさん出てきます。 –

+0

私はそれを逃したとは信じられません...ありがとう! –

+0

@TamásSzelei:最高のことに... :-) –