struct S
{
vector<int> v;
void method()
{
begin(v);
}
};
上面的代码片段编译得很好,因为ADL,直到我添加
auto begin() { return begin(v); }
到类声明。在这一点上,C++ 忘记了 ADL,而是更喜欢S::begin
它甚至没有可行的重载,从而产生错误
error: no matching function for call to ‘S::begin(std::vector<int>&)’ begin(v);
有什么解决办法吗?我在问,因为在阅读了为什么在 C++11 中使用非成员开始和结束函数之后?,为了一致性,我开始在任何地方使用begin()
和end()
释放函数,但现在我在定义自己的函数begin()
和end()
方法后遇到冲突。
您正在使用begin
不合格的名称和不合格的名称查找
... 按如下所述检查作用域,直到找到至少一个任何类型的声明,此时查找停止并且不再检查进一步的作用域。
参考。
从您的成员函数的角度来看,提供名称的第一个作用域begin
是类作用域,因此它从该作用域填充重载集,并停止查找。
只有在此名称查找阶段之后,它才会尝试选择重载集之一,并决定没有任何匹配项。然后编译器不会返回并从下一个范围开始搜索,它只是放弃了。
您的选择是:
使用现有的容器成员函数而不是 free 函数(这比下面的显式限定版本略少冗长)
auto begin() { return v.begin(); }
改用限定名称
auto begin() { return ::std::begin(v); }
将正确的重载添加到类范围, using std::begin;
忽略那个,我忘了你不能在类范围内引入非成员名称using
。
将正确的重载注入成员函数体本身的较窄范围,因此搜索停止
auto begin() { using std::begin; return begin(v); }
首先停止提供begin
成员函数,而是begin
向封闭的命名空间添加非成员重载。这更现代并且避免了查找问题。
namespace N {
struct S { std::vector<int> v; };
std::vector<int>::iterator begin(S& s) { return s.v.begin(); }
// and end, cbegin, etc. etc.
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句