如何在不同的命名空间中指定重载运算符? 我在C++标准库中遇到了麻烦。下面的示例没有编译:(注意,这只是一个简单的示例,因此没有多大意义)
我想这与ADL/Koenig查找有关,但我真的不明白为什么找不到我的如何在不同的命名空间中指定重载运算符? 我在C++标准库中遇到了麻烦。下面的示例没有编译:(注意,这只是一个简单的示例,因此没有多大意义),c++,C++,我想这与ADL/Koenig查找有关,但我真的不明白为什么找不到我的操作符==。如果我想使用第一种更简单的find函数,那么最好的解决方案是什么 实际上,otherns来自第三方库的标题,因此我无法将我的操作符放入该标题中。规则非常复杂,我自己也没有完全掌握它们,但让我们看看是否能够理解它们(我想我们可以): 之所以找不到它,原因很简单:operator==在使用之前没有声明。与ADL无关。到现在为止,一直都还不错。我们理解这一点。让我们修复它: namespace nx { struct X
操作符==
。如果我想使用第一种更简单的find
函数,那么最好的解决方案是什么
实际上,
otherns
来自第三方库的标题,因此我无法将我的操作符放入该标题中。规则非常复杂,我自己也没有完全掌握它们,但让我们看看是否能够理解它们(我想我们可以):
之所以找不到它,原因很简单:operator==
在使用之前没有声明。与ADL无关。到现在为止,一直都还不错。我们理解这一点。让我们修复它:
namespace nx {
struct X {};
}
auto operator==(nx::X, nx::X) { return true; }
namespace ns {
auto foo(nx::X x1, nx::X x2) { return x1 == x2; }
}
auto global_foo()
{
return ns::foo(nx::X{}, nx::X{});
}
这行吗?是的,它编译并调用我们的操作符==
。这是正确的解决方案吗<斯特朗>不。因为如果我们加上这个:
namespace nx {
struct X {};
}
auto operator==(nx::X, nx::X) { return true; } // (1)
namespace ns {
template <class T> auto operator==(T, int) { return false; } // (2)
auto foo(nx::X x1, nx::X x2) { return x1 == x2; }
// error: no match for 'operator==' (operand types are 'nx::X' and 'nx::X')
}
auto global_foo()
{
return ns::foo(nx::X{}, nx::X{});
}
这里发生的事情是,ADL开始从nx
引入(1)
,现在(1)
与(2)
一起考虑。但是(1)
比(2)
更专业,因此(1)
的选择是正确的
如果您无法控制名称空间nx
,并且无法在那里添加运算符,那么我建议您使用可调用项,而不是依赖运算符。例如,不要使用std::find
将std::find_if
与您自己的谓词(lambda)一起使用,您可以精确控制要调用的方法/运算符。当我说“精确地”时,我指的是精确地:即::operator==(x1,x2)
(或您声明的任何名称空间),而不是x1==x2
您可以阅读Herb Sutter的这篇伟大文章的更多内容,只需在命名空间
otherns
中声明operator==
(查找将在命名空间范围内找到它)
您可以在第三方库的单独标题中执行此操作。您在全局名称空间中定义了
运算符==
(可能是由于误齿造成的)。依赖于参数的查找不会在那里找到它
运算符应与其(其中一个)参数在同一命名空间中声明:
namespace otherns {
class Property {
public:
const std::string &getName() const { return m_name; }
private:
std::string m_name;
};
bool operator==(const otherns::Property &a, const otherns::Property &b) {
return a.getName() == b.getName();
}
}
这一小小的更改使您的示例能够干净地编译。找不到它,因为依赖于参数的查找只在中查找。由于运算符位于全局命名空间中,因此从未考虑过它。这就是为什么您必须始终将运算符声明在与类相同的命名空间中的原因。您使用的库要么故意尝试禁止ADL,要么编写者犯有遗漏罪;我理解了开头的段落“首先,如果由常规非限定查找生成的查找集包含以下任何内容,则不考虑依赖于参数的查找:”“这意味着我的运算符将通过“非限定查找”找到(另外,我认为是省略而不是故意不允许)@PeterHull-不,不会。不在模板实例化内部(依赖名称是这里的问题)。继续阅读我链接的页面。问题是在模板定义点执行非限定查找。不是实例化的要点。
namespace nx {
struct X {};
}
auto operator==(nx::X, nx::X) { return true; }
namespace ns {
auto foo(nx::X x1, nx::X x2) { return x1 == x2; }
}
auto global_foo()
{
return ns::foo(nx::X{}, nx::X{});
}
namespace nx {
struct X {};
}
auto operator==(nx::X, nx::X) { return true; } // (1)
namespace ns {
template <class T> auto operator==(T, int) { return false; } // (2)
auto foo(nx::X x1, nx::X x2) { return x1 == x2; }
// error: no match for 'operator==' (operand types are 'nx::X' and 'nx::X')
}
auto global_foo()
{
return ns::foo(nx::X{}, nx::X{});
}
namespace nx {
struct X {};
}
auto operator==(nx::X, nx::X) { return true; } // (1)
namespace ns {
template <class T> auto operator==(T, T) { return false; } // (2)
auto foo(nx::X x1, nx::X x2) { return x1 == x2; } // calls (2)
}
auto global_foo()
{
return ns::foo(nx::X{}, nx::X{});
}
namespace nx {
struct X {};
auto operator==(nx::X, nx::X) { return true; } // (1)
}
namespace ns {
template <class T> auto operator==(T, T) { return false; } // (2)
auto foo(nx::X x1, nx::X x2) { return x1 == x2; } // calls (1)
}
auto global_foo()
{
return ns::foo(nx::X{}, nx::X{});
}
namespace otherns {
bool operator==(const otherns::Property &a, const otherns::Property &b) {
return a.getName() == b.getName();
}
}
namespace otherns {
class Property {
public:
const std::string &getName() const { return m_name; }
private:
std::string m_name;
};
bool operator==(const otherns::Property &a, const otherns::Property &b) {
return a.getName() == b.getName();
}
}