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

时间:2010-09-12 15:38:12

标签: c++ variables function declaration

此代码有效:

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

1 个答案:

答案 0 :(得分:14)

这是C ++的“最令人烦恼的解析”。一个快速的Google应该会有大量的详细信息。基本答案是肯定的,编译器 将其视为函数声明 - 而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“填充”到初始化列表中,并将其传递给std::string ctor,采用初始化列表 - 但这将是类型不匹配,因此代码无法编译。对于某些其他类型的类型(与std::string不同,具有初始化列表ctor),上面的转换将起作用(感谢上面引用中的“否则......”)。对于std::string,您必须使用当前替代方案之一,例如std::string s = std:string(...)

我为错误的建议解决方案道歉 - 在这种情况下,情况更糟,因为它混淆了一个可能过于混乱的问题,如果有什么需要仔细澄清,特别是在未来几年

相关问题