2010-09-12 135 views
12

此代码的工作:功能VS在C++变量声明

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++标准中定义?

回答

14

这是C++的“最烦人的解析”。一个快速的谷歌应该会有很多的细节点击。基本答案是,是的,编译器将它视为函数声明 - 而C++要求它这样做。你的编译器没有问题(至少在这方面)。

如果有任何的安慰,你有很多好的公司遇到这个问题。实际上,C++ 0x被添加了一个新的支持 - 初始化器语法已经很常见了,很大程度上是因为它避免了这种模糊性。使用它,你可以写这样的:

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

这将使清楚,括号中的内容意在值初始化s类型的参数来命名s功能。我不知道苹果是否有端口,但gcc从版本4.5(或左右)接受新的语法。

编辑:重读N3092,约翰内斯(和往常一样)很正确。适用的语言是(§8.5.4/ 3/5):“如果T有一个初始化程序列表构造函数,则参数列表由初始化程序列表构成一个参数;否则,参数列表由初始化程序的元素组成清单“。

所以,既然std::string有一个初始化列表构造,这将尝试“东西”两istreambuf_iterator s转换为初始化列表,并将其传递到std::string构造函数,它接受一个初始化列表 - 但是这将是一个类型不匹配,所以代码无法编译。对于某些其他类型(与std::string不同,不是有一个初始化程序列表ctor),上面的转换可以工作(感谢上面引用中的“否则...”)。在std::string的情况下,您必须使用当前的替代方法之一,例如std::string s = std:string(...)

我对不正确的建议修复表示歉意 - 在这种情况下,情况更糟,因为它混淆了一个可能过度混淆的问题,如果有什么需要仔细解释的话,尤其是在接下来的几个问题上年份。

+1

谢谢! [这里在WP](http://en.wikipedia.org/wiki/Most_vexing_parse)也是关于最令人头痛的解析的一个很好的解释。 – Albert 2010-09-12 16:14:29

+1

看起来上面的'std :: string'变量声明在C++ 0x中不起作用:因为'std :: string'有一个初始化列表构造函数,整个'{...}'将被视为单个参数,并将尝试初始化'initializer_list '参数并且无法编译:( – 2010-09-12 23:21:40

+1

@Johannes:是的,我认为你是对的,我想知道它是否会更好如果这是重新编写的,而不是考虑一个列表初始化程序,然后(只有当它不存在时)考虑其他ctors,如果相反它只是构建了一个超载集并选择了一个最佳匹配 - 可能与创建一个小调整initializer_list 相当于没有转换关于匹配的好处(条件是我只考虑了几分钟,以便可能会导致我错过的微妙(甚至是明显的)问题)。 – 2010-09-12 23:48:51