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::coutWrapstd::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
}