Alb*_*ert 12 c++ variables declaration function
此代码有效:
std::ifstream f(mapFilename.c_str());
std::string s = std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
ParseGameState(s);
Run Code Online (Sandbox Code Playgroud)
因此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);
Run Code Online (Sandbox Code Playgroud)
这是错误:
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&)
Run Code Online (Sandbox Code Playgroud)
所以它似乎s在这种情况下识别为函数声明而不是变量声明.
这是为什么?这是GCC 4.2.1(Apple版本)中的错误吗?或者GCC是否正确处理了这个问题?这在C++标准中是否未定义?
Jer*_*fin 14
这是C++的"最令人烦恼的解析".一个快速的Google应该会有大量的详细信息.基本的答案是yes,编译器是把它当作一个函数声明-和C++要求它这样做.你的编译器没有任何问题(至少在这方面).
如果它有任何安慰,那么你就会遇到很多好公司.实际上,C++ 0x添加了一个新的大括号初始化语法是很常见的,这在很大程度上是因为它避免了这种歧义.使用它,你可以写如下:
std::string s{std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()};
Run Code Online (Sandbox Code Playgroud)
这将清楚地表明大括号的内容是用于初始化的值s,而不是命名函数的参数类型s.我不知道Apple是否有它的端口,但是gcc接受了4.5版本(或左右)的新语法.
编辑:重读N3092,约翰内斯(像往常一样)非常正确.适用的语言是(§8.5.4/ 3/5):"如果T有一个初始化列表构造函数,则参数列表由初始化列表作为单个参数组成;否则,参数列表由初始化程序的元素组成清单".
因此,由于std::string有一个初始化列表构造函数,这将尝试将两个istreambuf_iterators "填充" 到初始化列表中,并将其传递给std::string带有初始化列表的ctor - 但这将是类型不匹配,因此代码可以编译.对于一些其他类型的类型(不像std::string根本不具备一个初始化列表构造函数)的改造上面会工作(以上报价感谢"否则......").在这种情况下std::string,你必须使用当前的替代品之一,如std::string s = std:string(...).
我为错误的建议修复道歉 - 在这种情况下,一个更糟糕的是因为它混淆了一个可能过于混乱的问题,如果有什么需要仔细澄清,特别是在未来几年.