为什么 range-for 找不到 std::istream_iterator 的开始和结束重载?
Why doesn't range-for find my overloads of begin and end for std::istream_iterator?
我有这样的代码
std::ifstream file(filename, std::ios_base::in);
if(file.good())
{
file.imbue(std::locale(std::locale(), new delimeter_tokens()));
for(auto& entry : std::istream_iterator<std::string>(file))
{
std::cout << entry << std::endl;
}
}
file.close();
std::istream_iterator<std::string>
的begin()
和end()
定义如下
template<class T>
std::istream_iterator<T> begin(std::istream_iterator<T>& stream)
{
return stream;
}
template<class T>
std::istream_iterator<T> end(std::istream_iterator<T>& stream)
{
return std::istream_iterator<T>();
}
这也是马克·纳尔逊在多布博士的《这里》中所写的。唉,代码无法在我的 Visual Studio 2012 上编译并显示错误消息
错误 C3312:找不到类型"std::istream_iterator<_Ty>"的可调用"开始"函数
和
错误 C3312:找不到类型"std::istream_iterator<_Ty>"的可调用"结束"函数
问题:是否有我没有注意到的东西,编译器中的错误(不太可能,但以防万一)或......嗯,有什么想法吗?
根据Xeo的建议,这个问题得到了相当大的清理。为了提供更多的背景和参考,这与我在 Stackoverflow 上的另一个问题有关,我想知道如何使基于行的解析比通常的循环更干净。从互联网上进行了一些编码和检查,我有一个工作草图如下
std::ifstream file(filename, std::ios_base::in);
if(file.good())
{
file.imbue(std::locale(std::locale(), new delimeter_tokens()));
for(auto& entry : istream_range<std::string>(file)
{
std::cout << entry << std::endl;
}
}
file.close();
但是我试图补救有轻微的障碍。我认为在编译失败的代码中编写看起来会更自然,而不是像
for(auto& entry : istream_range<std::string>(file)
请记下不同的迭代器。delimeter_tokens的定义就像 Nawaz 在这里善意展示的那样(代码不重复),istream_range如这里的代码合成博客所示。我认为开始和结束实现应该有效,正如前面提到的代码合成博客文章
最后一条规则(回退到独立的 begin() 和 end() 函数)允许我们非侵入性地将现有容器适应基于范围的 for 循环接口。
因此,我的问题具有所有(不)相关的背景。
如果对本机数组(T foo[N]
)和成员begin
/end
的特殊处理没有产生任何结果,则Ranged-for依赖于ADL。
§6.5.4 [stmt.ranged] p1
- 否则,分别
begin(__range)
end(__range)
和 BEGIN-EXPR 和 END-EXPR,其中begin
和end
使用依赖于参数的查找进行查找 (3.4.2)。出于此名称查找的目的,命名空间std
是关联的命名空间。
您的问题是,std::istream_iterator
的关联命名空间(显然)是namespace std
,而不是全局命名空间。
§3.4.2 [basic.lookup.argdep] p2
对于函数调用中
T
的每个参数类型,需要考虑一组零个或多个关联的命名空间和一组零个或多个关联的类。命名空间和类的集合完全由函数参数的类型 [...] 决定。
- 如果
T
是基本类型,则其关联的命名空间和类集均为空。- 如果
T
是类类型(包括联合),则其关联的类是:类本身;它是其成员的类(如果有的话);及其直接和间接基类。其关联的命名空间是其关联类所属的命名空间。此外,如果 T 是类模板专用化,则其关联的命名空间和类还包括:与为模板类型参数提供的模板参数的类型关联的命名空间和类 [...]。
请注意第二个项目符号的最后一部分(引用)。这基本上意味着使用作为全局命名空间成员的类作为模板参数可以使代码工作:
#include <iterator>
#include <iostream>
template<class T>
std::istream_iterator<T> begin(std::istream_iterator<T> is){
return is;
}
template<class T>
std::istream_iterator<T> end(std::istream_iterator<T>){
return std::istream_iterator<T>();
}
struct foo{};
std::istream& operator>>(std::istream& is, foo){
return is;
}
int main(){
for(foo f : std::istream_iterator<foo>(std::cin))
// ^^^
// make global namespace one of the associated namespaces
;
}
由于依赖于参数的查找,编译器尝试在std
命名空间中查找begin()
和end()
。如果你把你的函数放在那里,代码就会编译。
由于名称查找在C++中是一个复杂的问题,因此我不完全确定编译器的行为是否正确。
- 根据用户输入用字母填充矢量,并将"开始"和"结束"放在四肢
- 如何在 c++ 中确定一条指令(以字节为单位)在哪里结束,另一条指令从哪里开始?
- 如何显示函数开始、结束行和函数体?
- C++ 从具有开始位置和结束位置的列表中删除
- C++程序从主程序开始执行并在主程序结束?
- 如何使用Chrono或ctime libaray输入设置的开始和结束时间
- 是否可以在基于范围的 for 循环中使用模板化的开始/结束方法
- 重写自定义数组类的运算符/开始/结束
- 取代表开始/结束的数字对,并删除重叠
- 如何为一个类提供多个开始/结束代理
- 映射大小() > 0 但开始() == 结束()
- 将数组作为函数参数传递,并在其上调用开始/结束方法
- 正则表达式,捕获 4 个被 括起来的数字.或行开始/结束
- C++ 指针上的开始/结束 (arr) - 调用 'begin(int**&)' 没有匹配函数
- 重载指向集合的指针的开始/结束是否是个好主意
- 检测 D3D 挂钩中的帧开始/结束
- C ::P在循环开始结束时发出声音循环声音
- 三次样条:开始/结束段插值
- Std::regex,匹配字符串的开始/结束
- 匹配开始/结束分析调用