Шаблоны выражений C ++, неоднозначная перегрузка операторов - PullRequest
1 голос
/ 02 апреля 2019

Я пытаюсь реализовать векторные и матричные шаблоны выражений. У обоих есть оператор + перегрузка, но я получаю неоднозначную ошибку оператора.

Как я могу перегрузить операторы для матрицы и вектора, сохраняя эффекты шаблонов выражений?

Вот мой матричный шаблон суммы:

    template<typename E1, typename E2>
class MatSum: public MatExpression<MatSum<E1,E2>>{
    E1 const& _u;
    E2 const& _v;

public:
    MatSum(E1 const &u, E2 const &v): _u(u), _v(v){
        assert(u.height() == v.height() && u.width() == v.width());
    }

    double operator[](size_t i) const {return _u[i] + _v[i]; }

    size_t size() const {return _u.size();}
    size_t width() const {return _u.width();}
    size_t height() const {return _u.height();}
};

template<typename E1, typename E2>
MatSum<E1,E2> operator+(E1 const& u, E2 const& v){
    return MatSum<E1,E2>(u,v);
}

и вот шаблон векторной суммы:

template <typename E1, typename E2>
class VecSum : public VecExpression<VecSum<E1, E2>>{
    E1 const& _u;
    E2 const& _v;

public:
    VecSum(E1 const & u, E2 const &v): _u(u), _v(v){
        assert(u.size() == v.size());
    }

    double operator[](size_t i) const {return _u[i] + _v[i]; }
    size_t size() const {return _v.size(); }
};


template <typename E1, typename E2>
VecSum<E1, E2> operator+(E1 const &u, E2 const &v){
    return VecSum<E1,E2>(u,v);
}

И кусок кода, который вызывает ошибку:

    Vec v1 = {67.12,34.8,90.34};

    Vec v2 = {34.90,111.9,45.12};

    Vec sum = v1+v2;

Matrix m0 = {{1.0,1.0,1.0},{1.0,1.0,1.0},{1.0,1.0,1.0}};
    Matrix m1 = {{1.0,1.0,1.0},{1.0,1.0,1.0},{1.0,1.0,1.0}};

    Matrix summ = m0 + m0;

Ответы [ 2 ]

2 голосов
/ 02 апреля 2019

Шаблоны не могут быть специализированы с типом возврата.

В вашем случае компилятор не может выбрать, какой operator+ вызывать, поскольку они оба могут быть мгновенно активированы любыми двумя типами. Рассмотрим пример:

Vec v1 = {67.12,34.8,90.34};
Matrix m1 = {{1.0,1.0,1.0},{1.0,1.0,1.0},{1.0,1.0,1.0}};
auto sum = v1+m1;

Какой из двух операторов должен быть вызван здесь? Это неоднозначно для компилятора.

Вы можете сделать два не шаблонных оператора +, которые имеют (Vec, Vec) и (Matrix, Matrix) аргументы, или использовать SFINAE , чтобы проверить типы аргументов шаблонного оператора для некоторого условия и заменить необходимую operator+ специализацию.

1 голос
/ 02 апреля 2019

Там нет ничего, чтобы отличить ваши два шаблона, так что это неоднозначный вызов. Вам придется ограничить тот, который возвращает MatSum, для применения только к матричным аргументам, и / или тот, который возвращает VecSum, для применения только к векторным аргументам.

Предположим, вы добавили псевдоним члена using kind = Mat; к MatExpression и Matrix, а также using kind = Vec к VecExpression и Vector. Затем мы делаем класс черт

template<typename E1, typename E2, typename = typename E1::kind, typename = typename E2::kind>
struct Traits;

template<typename E1, typename E2>
struct Traits<E1, E2, Mat, Mat>
{
    using sum_type = MatSum<E1, E2>;
    // others, e.g. using prod_type = MatProd<E1, E2>;
};

template<typename E1, typename E2>
struct Traits<E1, E2, Vec, Vec>
{
    using sum_type = VecSum<E1, E2>;
    // others, e.g. using prod_type = VecProd<E1, E2>;
};

И некоторые шаблоны псевдонимов, например,

template<typename E1, typename E2>
using sum_t = typename Traits<E1, E2>::sum_type;

Затем мы можем ограничить нашу + перегрузку только в том случае, если существует Traits.

template<typename E1, typename E2>
sum_t<E1, E2> operator+(E1 const& u, E2 const& v){
    return sum_t<E1, E2>(u, v);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...