【问题标题】:Overload resolution for template operators in namespaces命名空间中模板运算符的重载解决方案
【发布时间】:2020-01-19 14:02:18
【问题描述】:

在输入命名空间时,我遇到了模板运算符重载的问题。考虑添加数组:

// 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
}

}

现在假设我在命名空间mylib::mysublib 中有一个Complex 类,它有自己的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+’

为什么从嵌套命名空间调用时找不到重载的运算符?重载的全部意义(在这个例子中)将是一个干净的语法。关于如何使其工作的任何想法,或者是否有可能?

【问题讨论】:

  • 您可能需要添加 [language-lawyer] 标签。 ADL 查找 en.cppreference.com/w/cpp/language/adl 让我头疼
  • 请在帖子中包含您的错误信息。此外,operator+ 缺少其定义。添加operator+的函数定义后我看不到任何错误。
  • @Maverobot 你是对的,它确实编译了。然后问题变得有点复杂,我更新了我的问题:我在嵌套命名空间中引入了一个类,它有自己的重载并且破坏了整个事情。
  • 您希望调用 DoubleArray&lt;N&gt; 重载吗?

标签: c++ namespaces operator-overloading overload-resolution


【解决方案1】:

Complexoperator+可以在Complex中声明为friend函数,不会污染全局命名空间。您的示例应在以下更改后编译。

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

  DoubleArray<2> _components;

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

根据C++ standard working draft N4140

如果在相同范围内为单个名称指定了两个或多个不同的声明,则称该名称为重载。

在您的情况下,两个 operator+ 函数在不同的命名空间中声明,因此不符合重载决议的条件。

当编译器找到第一个匹配 Complex operator+(const Complex&amp; rhs, const Complex&amp; lhs) 时,DoubleArray 不能隐式转换为 Complex。因此,您得到了no match for ‘operator+’ 错误。

【讨论】:

  • 就是这样,谢谢。我仍然不明白发生了什么。我原以为 ADL 能够区分 Complex 参数和 DoubleArray 参数。我还有其他几个 operator+ 的重载,我以前从未遇到过这个问题。关于我应该阅读什么以清除此问题的任何提示?
  • @KelemenMáté 用更多信息更新了我的答案。
【解决方案2】:

将您的第三个代码替换为

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&amp; rhs, const Complex&amp; lhs) {return Complex();} 的定义隐藏了意图操作符

【讨论】:

  • 我是投反对票的人,现在投了赞成票。对不起给您带来不便。我的错误印象是 ADL 会找到另一个运算符(可能是因为评论提到了 ADL),但当然不是这样。
  • @anonymous 是的,但是operator+ 不适用于Complex。 @Johannes 我不明白,为什么不是这样?是什么让 ADL 在这里失败了?
  • 解决方案是将两个函数都声明为friend,然后全局定义它们
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
相关资源
最近更新 更多