ADL 未按预期工作

发布自我
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是类作用域,因此它从该作用域填充重载集,并停止查找。

只有在此名称查找阶段之后,它才会尝试选择重载集之一,并决定没有任何匹配项。然后编译器不会返回并从下一个范围开始搜索,它只是放弃了。

您的选择是:

  1. 使用现有的容器成员函数而不是 free 函数(这比下面的显式限定版本略少冗长)

    auto begin() { return v.begin(); }
    
  2. 改用限定名称

    auto begin() { return ::std::begin(v); }
    
  3. 将正确的重载添加到类范围, using std::begin;

    忽略那个,我忘了你不能在类范围内引入非成员名称using

  4. 将正确的重载注入成员函数体本身的较窄范围,因此搜索停止

    auto begin() { using std::begin; return begin(v); }
    
  5. 首先停止提供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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章