Разрешение перегрузки для операторов шаблонов в пространствах имен - PullRequest
1 голос
/ 19 января 2020

У меня возникли некоторые проблемы с перегрузками операторов шаблонов при входе в пространства имен. Рассмотрим добавление массивов:

// overloads.hpp
#include <array>

namespace mylib {

template <size_t N>
using DoubleArray = std::array<double,N>;

template <size_t N>
DoubleArray<N> operator+( const DoubleArray<N>& lhs, const DoubleArray<N>& rhs ) {return DoubleArray<N>();}

}

Проверка этого в namespace mylib работает как задумано.

// test.cpp
#include "overloads.hpp"

namespace mylib {

void test()
{
    DoubleArray<3> a({1.0,0.0,0.0});
    DoubleArray<3> b({0.0,1.0,0.0});
    DoubleArray<3> c(a+b);                        // <-- ok
}

}

Теперь предположим, что у меня есть класс Complex в пространстве имен mylib::mysublib, который имеет его собственный operator+ и конструктор из DoubleArray (этот конструктор должен быть явным, чтобы предотвратить неявное преобразование):

// nested.cpp
#include "overloads.hpp"

namespace mylib {
    namespace mysublib {

        struct Complex
        {
            Complex() {};
            explicit Complex( const DoubleArray<2>& components );

            DoubleArray<2> _components;
        };

        Complex operator+(const Complex& rhs, const Complex& lhs) {return Complex();}



        void testNested()
        {
            DoubleArray<2> a({1.0,0.0});
            DoubleArray<2> b({0.0,1.0});
            DoubleArray<2> c(a+b);                        // <-- no match for ‘operator+’
            DoubleArray<2> d( mylib::operator+(a,b) );    // <-- ok
        }

    }
}

Сообщение об ошибке:

error: no match for ‘operator+’ (operand types are ‘mylib::DoubleArray<2> {aka std::array<double, 2>}’ and ‘mylib::DoubleArray<2> {aka std::array<double, 2>}’)
     DoubleArray<2> c(a+b);                        // <-- no match for ‘operator+’

Почему нельзя перегруженный оператор будет найден при вызове из вложенного пространства имен? Весь смысл перегрузки (в этом примере) будет в чистом синтаксисе. Любые идеи о том, как заставить это работать, или если это вообще возможно?

Ответы [ 2 ]

1 голос
/ 19 января 2020

operator+ из Complex может быть объявлено как friend функция в Complex, которая не загрязняет глобальное пространство имен. Ваш пример должен скомпилироваться после следующего изменения.

struct Complex {
  Complex(){};
  explicit Complex(const DoubleArray<2>& components);

  DoubleArray<2> _components;

  friend Complex operator+(const Complex& rhs, const Complex& lhs) { return Complex(); }
};

В соответствии со C ++ стандартным рабочим проектом N4140 ,

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

В вашем случае две функции operator+ объявлены в другом пространстве имен и, следовательно, не являются подходит для разрешения перегрузки.

Когда компилятор находит первое совпадение Complex operator+(const Complex& rhs, const Complex& lhs), DoubleArray не может быть неявно преобразовано в Complex. Следовательно, вы получили ошибку no match for ‘operator+’.

1 голос
/ 19 января 2020

Замените ваш третий код на

namespace mylib {
    namespace mysublib {


        struct Complex
        {
            Complex() {};
            explicit Complex( const DoubleArray<2>& components );

            DoubleArray<2> _components;
        };

        //Complex operator+(const Complex& rhs, const Complex& lhs) {return Complex();}



        void testNested()
        {
            DoubleArray<2> a({1.0,0.0});
            DoubleArray<2> b({0.0,1.0});
            DoubleArray<2> c(a+b);                        // <-- no match for ‘operator+’
            DoubleArray<2> d( mylib::operator+(a,b) );    // <-- ok
        }

    }
}

, затем он скомпилируется.

Определение Complex operator+(const Complex& rhs, const Complex& lhs) {return Complex();} скрывает намеренный оператор

...