Шаблон вычета жалоб неоднозначных кандидатов - PullRequest
0 голосов
/ 13 ноября 2018

Я намереваюсь реализовать оператор умножения моих классов "Разреженный вектор" и "Вектор".В следующем демонстрационном примере с упрощенным кодом показана моя проблема

Класс Vector в Vector.hpp

#pragma once

template <typename T>
class Vector 
{
public:
    Vector() {}

    template <typename Scalar>
    friend Vector operator*(const Scalar &a, const Vector &rhs)     // #1
    {
        return Vector();
    }
};

разреженный вектор класс в SpVec.hpp

#pragma once
#include "Vector.hpp"

template <typename T>
class SpVec 
{
public:
    SpVec() {}

    template <typename U>
    inline friend double operator*(const SpVec &spv, const Vector<U> &v)   // #2
    {
        return 0.0;
    }
};

Тестовый код в main.cpp :

#include "Vector.hpp"
#include "SpVec.hpp"


#include <iostream>

int main() 
{
    Vector<double> v;

    SpVec<double> spv;

    std::cout << spv * v;
    return 0;
}

Я создаю тестовую программу с

g++ main.cpp -o test

, что приводит к неоднозначной ошибке вывода шаблона

main.cpp: In function ‘int main()’:
main.cpp:13:26: error: ambiguous overload for ‘operator*’ (operand types are ‘SpVec<double>’ and ‘Vector<double>’)
        std::cout << spv * v;
                    ~~~~^~~
In file included from main.cpp:2:0:
SpVec.hpp:12:26: note: candidate: double operator*(const SpVec<T>&, const Vector<U>&) [with U = double; T = double]
    inline friend double operator*(const SpVec &spv, const Vector<U> &v)   // #2
                        ^~~~~~~~
In file included from main.cpp:1:0:
Vector.hpp:10:19: note: candidate: Vector<T> operator*(const Scalar&, const Vector<T>&) [with Scalar = SpVec<double>; T = double]
    friend Vector operator*(const Scalar &a, const Vector &rhs)     // #1

Я ожидаю, что определение метода #2 ближе к моему вызову.

Пожалуйста, помогите мне понятькак возникает неоднозначная ошибка и как ее решить.

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

Мне пришла в голову другая идея, что информацию о предыдущем типе Scalar можно использовать с функцией SFAINE , включенной стандартной библиотечной структурой c++11 struct std::enable_if.

Коды:

Vector.hpp

#pragma once

#include <iostream>
#include <type_traits>

template <typename T>
class Vector
{
public:
    Vector() {}

    template <typename Scalar>
    typename std::enable_if<std::is_arithmetic<Scalar>::value, Vector<T>>::type
    operator*(const Scalar &rhs) const// #1
    {
        std::cout << "Vector * Scalar called." << std::endl;
        return Vector();
    }

    template <typename Scalar>
    inline friend typename std::enable_if<std::is_arithmetic<Scalar>::value, Vector<T>>::type
    operator*(const Scalar &lhs, const Vector &rhs)
    {
        std::cout << "Scalar * Vector called." << std::endl;
        return Vector();
    }
};

SpVec.hpp

#pragma once
#include "Vector.hpp"

#include <iostream>

template <typename T>
class SpVec
{
public:
    SpVec() {}

    template <typename U>
    inline double operator*(const Vector<U> &rhs) const // #2 as member function
    {
        std::cout << "SpVec * Vector called" << std::endl;
        return 0.0;
    }

    template <typename U>
    inline friend double operator*(const Vector<U> &lhs, const SpVec &rhs)
    {
        std::cout << "Vector * SpVec called" << std::endl;
        return 0.0;
    }
};

main.cpp

#include "SpVec.hpp"
#include "Vector.hpp"

#include <iostream>

int main()
{
    Vector<double> v;
    SpVec<double> spv;

    double a = spv * v;
    a = v * spv;

    Vector<double> vt;
    vt = v * 2.0;
    vt = 2.0 * v;

    return 0;
}

Сборка программы с c++11

g++ -std=c++11 main.cpp -o test

Результат:

SpVec * Vector called.
Vector * SpVec called.
Vector * Scalar called.
Scalar * Vector called.
0 голосов
/ 13 ноября 2018

Аргументом для operator* являются SpVec<double> и Vector<double>.Может быть разрешено до

operator*(const Scalar &a, const Vector &rhs) с scalar как SpVec<double> и rhs как Vector<double>.

Также может быть разрешено до

operator*(const SpVec &spv, const Vector<U> &v) с spv как SpVec<double> и U как double.

Один из способов решения этой проблемы - включить Vector::operator* в функцию, не являющуюся другом.

Vector operator*(const Scalar &a)     // #1
{
    //The other argument here will be accessed using this pointer.
    return Vector();
}

и выможно назвать это как

int main() 
{
   Vector<double> v;
   SpVec<double> spv;
   std::cout << spv * v; // will call #2
   v * spv;              //will call #1
   return 0;
}
...