C++ 与ADL相比,更喜欢某些功能

C++ 与ADL相比,更喜欢某些功能,c++,argument-dependent-lookup,C++,Argument Dependent Lookup,我想使用基于范围的for在UTF8编码的std::string中迭代unicode代码点。我已在全局命名空间中定义了自己的begin和end,但首选std命名空间中的begin和end(即ADL找到的)。有没有办法让我更喜欢自己的功能 例如: const char* begin(const std::string& s) { std::cout << "BEGIN"; return s.data(); } const char* end(const std:

我想使用基于范围的
for
在UTF8编码的
std::string
中迭代unicode代码点。我已在全局命名空间中定义了自己的
begin
end
,但首选
std
命名空间中的
begin
end
(即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;
}
const char*begin(const std::string&s){

std::coutWrap
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;
    }
}
#包括
#包括
模板
结构自定义容器{
S&S;
自定义容器(S&S):S(S){}
自动开始()->decltype(s_2;u.begin()){
std::cout decltype(s_ux.end()){
标准::cout6.5.4/1:

(…)开始表达式和结束表达式的确定如下:

-如果
\u range
是数组类型,则开始表达式和结束表达式为
\uuuu range
\uuu range+\uu-bound
分别为(…)

-如果
\u range
是类类型,则不合格的ID
开始
结束
为 在类
\u range
的范围内进行查找,就像通过类成员访问一样 查找(3.4.5),如果其中一个(或两个)查找到至少一个声明, begin expr和end expr是
\u range.begin()
\u range.end()
, 分别

-否则,begin expr和end expr是
begin(\uu范围)
end(_范围)
,其中
begin
end
用 参数相关查找(3.4.2)。用于此名称 查找,命名空间
std
是一个关联的命名空间

因此,换句话说,它将调用
std::string
begin
end
成员函数(第二个列表项目符号)。正确的解决方案是按照的答案提供包装类

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

您还可以编写typedef以减少键入:

typedef custom_string<std::string> cs;

for (char c : cs(t)) {
    std::cout << c;
}
typedef自定义字符串cs;
用于(字符c:cs(t)){

std::cout最干净的方法,至少在使用点上,这是为了特殊迭代的目的标记您的类型

首先,一些机械:

template<class Mark, class T>
struct marked_type {
  T raw;
  marked_type(T&& in):raw(std::forward<T>(in)) {}
};
template<typename Mark, typename T>
marked_type<Mark, T> mark_type( T&& t ) {
  return {std::forward<T>(t)};
}
现在,不管传入的容器是什么,我们都会向后迭代。对于这样的构造,需要为右值“创建副本”:

for( char c: mark_type<reverse_iteration>(mark_type<strange_iteration>(s))
namespace adl_helper {
  using std::begin; using std::end;
  template<typename T>
  auto adl_begin(T&& t)->decltype( begin(std::forward<T>(t)) ); // no implementation
  template<typename T>
  auto adl_end(T&& t)->decltype( end(std::forward<T>(t)) ); // no implementation
  // add adl_cbegin, adl_rbegin etc in C++14
}
然后用
adl\u helper::adl\u begin
替换我上面代码中
decltype
s中的
std::begin
,它模拟了(a:b)
循环查找
begin
end
的方式(不是完美的,但更好)

C++1y可能会附带一些机器,以消除上述黑客的需要


运行的示例代码:

注意:您的基本假设是错误的:这里没有ADL,
s
是一个
std::string
所以
for(char c:s)
的行为就像使用成员表单
s.begin()
s.end()
,而不是非成员表单
begin/code>和
end
(参见remyabel的答案)@gx_uuz是的,下面的一些答案提到了这一点。我将其颠倒过来,认为非成员
begin
首先尝试,成员
begin
第二次尝试。@uk4321您可能感兴趣。
for( char c : mark_type<reverse_iteration>(s) )
for( char c: mark_type<reverse_iteration>(mark_type<strange_iteration>(s))
namespace adl_helper {
  using std::begin; using std::end;
  template<typename T>
  auto adl_begin(T&& t)->decltype( begin(std::forward<T>(t)) ); // no implementation
  template<typename T>
  auto adl_end(T&& t)->decltype( end(std::forward<T>(t)) ); // no implementation
  // add adl_cbegin, adl_rbegin etc in C++14
}