比ADL更喜欢某些功能

uk4*_*321 7 c++ argument-dependent-lookup

我想使用基于范围for来迭代UTF8编码的unicode代码点std::string.我定义我自己begin,并end在全局命名空间,但beginendstd命名空间中被优先(即那些由ADL找到).有什么方法可以选择我自己的功能吗?

例:

const char* begin(const std::string& s) {
    std::cout << "BEGIN";
    return s.data();
}

const char* end(const std::string& s) {
    std::cout << "END";
    return s.data() + s.length();
}

int main() {
    std::string s = "asdf";

    for (char c : s)
        std::cout << c;
}
Run Code Online (Sandbox Code Playgroud)

我希望它打印BEGINENDasdf(或ENDBEGINasdf)但它打印asdf.

除了for使用合格的名称做手册之外别无他法吗?

Ant*_*ony 6

包装std::string你自己的类型.通过使其成为模板,您可以自定义任何现有容器并向其添加自己的范围逻辑.它与你的第一次尝试甚至没有什么不同.

#include <string>
#include <iostream>

template <typename S>
struct custom_container {
    S &s_;

    custom_container (S &s) : s_(s) {}

    auto begin() -> decltype(s_.begin()) {
        std::cout << "BEGIN";
        return s_.begin();
    }

    auto end() -> decltype(s_.end()) {
        std::cout << "END";
        return s_.end();
    }
};

template <typename S>
custom_container make_container (S &s) {
     return custom_container <S> (s);
}


int main () {
    std::string t = "asdf";
    auto s = make_container(t);

    for (char c : s) {
        std::cout << c;
    }
}
Run Code Online (Sandbox Code Playgroud)

输出

BEGINENDasdf


小智 6

N3337 6.5.4/1:

(...)begin-exprend-expr确定如下:

-如果_RangeT是一个数组类型,开始-EXPR最终EXPR__range__range + __bound分别(...);

- 如果_RangeT是类类型,则在类的范围内查找unquali fi ed-id s begin,end_RangeT好像通过类成员访问查找(3.4.5),以及是否(或两者)找到至少一个声明, begin-exprend-expr分别是__range.begin()__range.end();

-否则,开始-EXPR最终EXPRbegin(__range)end(__range)表示,其中beginend被查找与参数相关的查找(3.4.2).出于此名称查找的目的,namespace std是关联的命名空间.

换句话说,它将调用std::string's' beginend成员函数(第二个列表项目符号).正确的解决方案是提供一个包装类,如安东尼的答案所示.

注意:如果使用-std=c++1y,可以省略尾随的decltype.

您还可以编写一个typedef来减少输入:

typedef custom_string<std::string> cs;

for (char c : cs(t)) {
    std::cout << c;
}
Run Code Online (Sandbox Code Playgroud)