代码之家  ›  专栏  ›  技术社区  ›  Albert

函数与变量声明在C++中的应用

  •  12
  • Albert  · 技术社区  · 15 年前

    此代码有效:

    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 在这种情况下,作为函数声明而不是变量声明。

    为什么会这样?这是GCC4.2.1(Apple Build)中的漏洞吗?或者GCC处理得正确吗?这在C++标准中没有定义吗?

    1 回复  |  直到 15 年前
        1
  •  14
  •   Jerry Coffin    15 年前

    这是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 进入初始值设定项列表,并将其传递给 STD::字符串 获取初始值设定项列表的构造函数——但这可能是类型不匹配,因此代码无法编译。对于其他类型 STD::字符串 有一个初始值设定项列表ctor)上面的转换可以工作(多亏了上面引号中的“否则…”)。在情况下 STD::字符串 ,您必须使用当前的备选方案之一,例如 std::string s = std:string(...) .

    我为不正确的建议修复方法道歉——在这种情况下,更糟的是,它混淆了一个问题,这个问题本身可能过于混乱,如果有任何问题需要仔细澄清,特别是在接下来的几年里。

    推荐文章