C++ 中的函数与变量声明
此代码有效:
std::ifstream f(mapFilename.c_str());
std::string s = std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
ParseGameState(s);
其中 mapFilename
是 std::string
和 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++ 标准中未定义的吗?
This code works:
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&);
.
And this does not:
std::ifstream f(mapFilename.c_str());
std::string s(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
ParseGameState(s);
This is the error:
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&)
So it seems that it recognizes s
as a function declaration and not a variable declaration in this case.
Why is that? Is this a bug in GCC 4.2.1 (Apple build)? Or does GCC handles this correctly? Is this undefined in the C++ standard?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是 C++ 的“最令人烦恼的解析”。快速谷歌一下,应该会出现很多带有很多细节的点击。基本答案是肯定的,编译器将其视为函数声明,而 C++ 要求它这样做。您的编译器没有任何问题(至少在这方面)。
如果你能感到安慰的话,那就是你遇到了很多好伙伴。事实上,C++0x 添加新的大括号初始化语法是很常见的,很大程度上是因为它避免了这种歧义。使用它,您可以编写如下内容:
这将清楚地表明大括号的内容是用于初始化
s
的值,而不是 函数参数类型命名为s
。我不知道 Apple 是否有它的端口,但 gcc 从 4.5 版(左右)开始接受新语法。编辑:重读 N3092,约翰内斯(像往常一样)非常正确。适用的语言是(§8.5.4/3/5):“如果 T 有一个初始化器列表构造函数,则参数列表由初始化器列表作为单个参数组成;否则,参数列表由初始化器的元素组成列表。”
因此,由于
std::string
有一个初始化列表构造函数,这将尝试将两个istreambuf_iterator
“填充”到初始化列表中,并将其传递给 < code>std::string 构造函数接受初始化列表——但这会导致类型不匹配,因此代码无法编译。对于某些其他类型(与std::string
不同,没有有初始化列表构造函数),上面的转换将起作用(感谢“否则...”)在上面的引用中)。对于std::string
,您必须使用当前的替代方案之一,例如std::string s = std:string(...)
。我对不正确的建议修复表示歉意——在这种情况下,情况变得更糟,因为它混淆了一个本身可能会过度混乱的问题,如果有什么需要仔细澄清的话,尤其是在接下来的几年里。
This is C++'s "most vexing parse." A quick Google for that should turn up lots of hits with lots of details. The basic answer is that yes, the compiler is treating it as a function declaration -- and C++ requires that it do so. There's nothing wrong with your compiler (at least in this respect).
If it's any comfort, you have lots of good company in having run into this. In fact, it's sufficiently common that C++0x is added a new brace-initializer syntax, in large part because it avoids this ambiguity. Using it, you could write something like:
That will make it clear that the contents of the braces are intended to be values for initializing
s
, not types of parameters to a function nameds
. I don't know if Apple has a port of it yet, but gcc accepts the new syntax as of version 4.5 (or so).Edit: Rereading N3092, Johannes is (as usual) quite correct. The applicable language is (§8.5.4/3/5): "If T has an initializer-list constructor, the argument list consists of the initializer list as a single argument; otherwise, the argument list consists of the elements of the initializer list."
So, since
std::string
has an initializer-list constructor, this would attempt to "stuff" the twoistreambuf_iterator
s into an initializer list, and pass that to thestd::string
ctor that takes an initializer list -- but that would be a type mismatch, so the code can't compile. For some other type type that (unlikestd::string
did not have an initializer-list ctor) the transformation above would work (thanks to the "otherwise..." in the quote above). In the case ofstd::string
, you'd have to use one of the current alternatives such asstd::string s = std:string(...)
.I apologize for the incorrect suggested fix -- in this case, one that's all the worse because it confuses an issue that will probably be excessively confusing on its own, and if anything will need careful clarification, especially over the next few years.