如何防止ADL期间的过度阴影?

时间:2020-08-10 09:13:04

标签: c++ templates argument-dependent-lookup

假设我有一个扩展(STL)容器并提供惯用的begin成员函数的类:

#include <vector>

template <typename Cont>
struct Bar {
    Cont c;
    auto my_begin() { return begin(c); }
};

int main() {
    Bar<std::vector<int>> b;
    b.my_begin();
}

通过ADL,我不必在std::调用之前指定begin()。很好,因为std::begin(v)总是会尝试调用v.begin(),因此用户可能想使用没有.begin()接口的自定义容器,因此如果他定义自己的自由功能{ {1}},begin(v)将使用它。 但是,如果我也将Bar重命名为my_begin,似乎ADL将不再起作用,好像它已经被遮盖了一样。编译器只会抱怨无法在类范围内找到匹配的调用来开始:

begin

当然,通过编写prog.cc: In instantiation of 'auto Bar<Cont>::begin() [with Cont = std::vector<int>]': prog.cc:11:13: required from here prog.cc:6:27: error: use of 'auto Bar<Cont>::begin() [with Cont = std::vector<int>]' before deduction of 'auto' 6 | auto begin() { return begin(c); } | ^~~~~ prog.cc:6:32: error: no matching function for call to 'Bar<std::vector<int> >::begin(std::vector<int>&)' 6 | auto begin() { return begin(c); } | ~~~~~^~~ prog.cc:6:10: note: candidate: 'auto Bar<Cont>::begin() [with Cont = std::vector<int>]' 6 | auto begin() { return begin(c); } | ^~~~~ prog.cc:6:10: note: candidate expects 0 arguments, 1 provided ,代码将再次运行,但这仅表示排除了ADL。除了重命名成员函数外,我还能做什么?

2 个答案:

答案 0 :(得分:6)

您可以只使用两步方法:

    auto begin() { 
        using std::begin;   //1
        return begin(c);    //2
    }

1:将std::begin考虑在内
2:如果c在其命名空间中有begin(),请调用它,否则默认为std::begin()

您可以详细了解here

答案 1 :(得分:4)

一种解决方案是编写一个独立的辅助函数,专门在begin上使用ADL:

template <typename C>
decltype(auto) adl_begin(C && c)
{
    using std::begin;
    return begin(std::forward<C>(c));
}

然后在您的班级中致电adl_begin

这里有using std::begin;部分,因此该函数甚至可以用于基本数组。