C++ 中的函数与变量声明

发布于 2024-09-19 00:14:28 字数 1088 浏览 5 评论 0原文

此代码有效:

std::ifstream f(mapFilename.c_str());
std::string s = std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
ParseGameState(s);

其中 mapFilenamestd::stringvoid 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

过潦 2024-09-26 00:14:28

这是 C++ 的“最令人烦恼的解析”。快速谷歌一下,应该会出现很多带有很多细节的点击。基本答案是肯定的,编译器将其视为函数声明,而 C++ 要求它这样做。您的编译器没有任何问题(至少在这方面)。

如果你能感到安慰的话,那就是你遇到了很多好伙伴。事实上,C++0x 添加新的大括号初始化语法是很常见的,很大程度上是因为它避免了这种歧义。使用它,您可以编写如下内容:

std::string s{std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()};

这将清楚地表明大括号的内容是用于初始化 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:

std::string s{std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()};

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 named s. 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 two istreambuf_iterators into an initializer list, and pass that to the std::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 (unlike std::string did not have an initializer-list ctor) the transformation above would work (thanks to the "otherwise..." in the quote above). In the case of std::string, you'd have to use one of the current alternatives such as std::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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文