这段代码的工作原理:
std::ifstream f(mapFilename.c_str());
std::string s = std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
ParseGameState(s);
Whereby mapFilename
is an std::string
and void ParseGameState(const std::string&);
.
这并不:
std::ifstream f(mapFilename.c_str());
std::string s(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
ParseGameState(s);
这是错误:
game.cpp: In member function ‘int Game::LoadMapFromFile(const std::string&)’:
game.cpp:423: error: no matching function for call to ‘ParseGameState(std::string (&)(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> > (*)()))’
game.cpp:363: note: candidates are: ParseGameState(const std::string&)
所以看起来它认识s
在这种情况下,作为函数声明而不是变量声明。
这是为什么?这是 GCC 4.2.1(Apple 版本)中的错误吗?或者 GCC 是否正确处理这个问题?这是 C++ 标准中未定义的吗?
这是 C++ 的“最令人烦恼的解析”。快速谷歌一下,应该会出现很多带有很多细节的点击。基本答案是肯定的,编译器is将其视为函数声明——C++ 要求它这样做。您的编译器没有任何问题(至少在这方面)。
如果你能感到安慰的话,那就是你遇到了很多好伙伴。事实上,C++0x 添加新的大括号初始化语法是很常见的,很大程度上是因为它避免了这种歧义。使用它,您可以编写如下内容:
std::string s{std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()};
这将清楚地表明大括号的内容旨在作为初始化值s
, not名为函数的参数类型s
。我不知道 Apple 是否有它的端口,但 gcc 从 4.5 版(左右)开始接受新语法。
编辑:重读 N3092,约翰内斯(像往常一样)非常正确。适用的语言是(§8.5.4/3/5):“如果 T 有一个初始化器列表构造函数,则参数列表由初始化器列表作为单个参数组成;否则,参数列表由初始化器的元素组成列表。”
所以,自从std::string
有一个初始化列表构造函数,这将尝试“填充”这两个istreambuf_iterator
s 到初始化列表中,并将其传递给std::string
ctor 接受一个初始化列表——但这会导致类型不匹配,因此代码无法编译。对于其他一些类型(不同于std::string
did not有一个初始化列表构造函数)上面的转换将起作用(感谢上面引用中的“否则...”)。如果是std::string
,您必须使用当前的替代方案之一,例如std::string s = std:string(...)
.
我对不正确的建议修复表示歉意——在这种情况下,情况变得更糟,因为它混淆了一个本身可能会过度混乱的问题,如果有什么需要仔细澄清的话,尤其是在接下来的几年里。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)