眠りネ*_*ネロク 4 c++ templates overloading using-declaration c++11
假设我有以下Data课程:
struct Data {
char foo[8];
char bar;
};
Run Code Online (Sandbox Code Playgroud)
和以下函数,my_algorithm需要一对char *(类似于STL算法):
void my_algorithm(char *first, char *last);
Run Code Online (Sandbox Code Playgroud)
对于Data的foo数据成员,而不是my_algorithm()像这样调用:
Data data;
my_algorithm(data.foo, data.foo + 8);
Run Code Online (Sandbox Code Playgroud)
我可以使用std::begin()和std::end()便利功能模板:
my_algorithm(std::begin(data.foo), std::end(data.foo));
Run Code Online (Sandbox Code Playgroud)
我想实现类似于Data的bar数据成员的功能。也就是说,而不是写:
my_algorithm(&data.bar, &data.bar + 1);
Run Code Online (Sandbox Code Playgroud)
我想写一些像:
my_algorithm(begin(data.bar), end(data.bar));
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,我定义了以下两个普通(非模板)函数:
char* begin(char& c) { return &c; }
char* end(char& c) { return &c + 1; }
Run Code Online (Sandbox Code Playgroud)
这样我就可以编写如下代码:
Data data;
using std::begin;
using std::end;
my_algorithm(begin(data.foo), end(data.foo)); // ok - std::begin()/std::end()
my_algorithm(begin(data.bar), end(data.bar)); // Error!!!
Run Code Online (Sandbox Code Playgroud)
使用using上面的声明,我期望std::begin()/ std::end()和::begin()/ ::end()分别处于同一重载集中。由于函数::begin()和::end()是后一个调用的完美匹配,并且它们不是模板,因此,我希望最后一个调用my_algorithm()能够匹配它们。但是,根本不考虑普通功能。结果,编译失败,因为std::begin()和std::end()调用不匹配。
基本上,后面的调用就像我写的一样:
my_algorithm(begin<>(data.bar), end<>(data.bar));
Run Code Online (Sandbox Code Playgroud)
也就是说,重载解析过程仅考虑功能模板(即std::begin()/ std::end()),而不考虑普通功能(即不::begin()/ ::end())。
它仅如预期,如果我完全有资格呼叫工作::begin()/ ::end():
my_algorithm(::begin(data.bar), ::end(data.bar));
Run Code Online (Sandbox Code Playgroud)
我在这里想念什么?
让我们得到一个完整的,可复制的示例:
#include <iterator>
char* begin(char& c) { return &c; }
char* end(char& c) { return &c + 1; }
namespace ns {
void my_algorithm(char *first, char *last);
void my_function() {
using std::begin;
using std::end;
char c = '0';
my_algorithm(begin(c), end(c));
}
}
Run Code Online (Sandbox Code Playgroud)
当您对begin(c)和进行非限定调用时end(c),编译器将进行非限定名称查找的过程(在cppreference的与参数相关的查找页面上进行了介绍)。
对于常规的不合格名称查找,此过程大致从当前所在的名称空间开始(::ns在这种情况下),并且仅在找不到特定名称的情况下才移出名称空间。
如果函数调用是不合格的,因为它是在这里与begin(c)和end(c),参数依赖查找可以发生,这发现在相同的命名空间的类型的功能的论点宣布为无功能,通过延伸通过找到重载集合的过程“相关联的命名空间。”
但是,在这种情况下,char它是基本类型,因此依赖于参数的查找不允许我们查找全局::begin和::end函数。
对于基本类型的参数,关联的名称空间和类的集合为空
相反,因为我们已经有了using std::begin; using std::end;,编译器已经可以看到功能begin(...)和end(...)-namely那些在命名空间中定义::std-without有一个命名空间,从搬出::ns来::。因此,编译器使用这些函数,并且编译失败。
值得一提的是,using std::begin; using std::end;也找到自定义块的编译器::begin和::end即使你是里面放置它们::ns。
您可以做的是编写自己的begin和end:
#include <iterator>
namespace ns {
char* begin(char& c) { return &c; }
char* end(char& c) { return &c + 1; }
template <typename T>
auto begin(T&& t) {
using std::begin;
// Not unbounded recursion if there's no `std::begin(t)`
// or ADL `begin(t)`, for the same reason that our
// char* begin(char& c); overload isn't found with
// using std::begin; begin(c);
return begin(t);
}
template <typename T>
auto end(T&& t) {
using std::end;
return end(t);
}
void my_algorithm(char *first, char *last);
void my_function() {
char c = '0';
my_algorithm(ns::begin(c), ns::end(c));
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
351 次 |
| 最近记录: |