Странное поведение операторов с CRTP и специализацией шаблонов - PullRequest
0 голосов
/ 06 января 2012

Я пишу векторный шаблон с несколькими специализациями, чтобы в зависимости от размера были указаны именованные методы доступа для первых нескольких элементов вектора (таких как x, y, z, w). Ответ Кенни ТМ очень помог в этом.Я также добавил форму Любопытно повторяющийся шаблон , чтобы иметь возможность использовать операторы естественным образом.Вот базовый класс и специализация с добавленными функциями (для краткости опущено большинство реализаций-членов):

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;

Этот код тоже работает:

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

Но этот код не работает:

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

Компилятор говорит:

ошибка: нет совпадения для 'operator <<' в 'qDebug () () << v1.Vector <3> ::. VectorImpl :: operator + [with int Dim= 3, V = Vector <3>, ItemType = float] ((* (const Vector <3> *) (& v2))) '

Что происходит?Почему тип v1 + v2 отличается при присвоении переменной?Что я должен сделать, чтобы сделать эту компиляцию?

1 Ответ

4 голосов
/ 06 января 2012

Дайте выходной функции ссылку const , или rvalues ​​(например, временное значение, являющееся результатом вашего добавления) не будет привязываться к ней (и не будет действительных констант, в этом отношении):

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

Также объявите toString как const:

QString toString() const;
//                 ^^^^^
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...