Std::ifstream使用临时Std::string()作为构造函数参数时行为怪异

std::ifstream behaves weirdly with temporary std::string() as constructor argument

本文关键字:Std 构造函数 参数 ifstream string      更新时间:2023-10-16

我试着编译一个简单的程序

int main(int argc, char* argv[]) {
    std::ifstream strings(std::string(argv[1]));
    std::string line;
    while (!strings.eof()) {
        strings >> line;
    }
}

并得到奇怪的错误:

error: request for member ‘eof’ in ‘strings’, which is of non-class type ‘std::ifstream(std::string*) {aka std::basic_ifstream<char>(std::basic_string<char>*)}’

如果改成

std::ifstream strings(argv[1]);

都能很好地编译。

这里发生了什么?编译器为gcc 4.7和4.9

这有时被称为最令人烦恼的解析: strings的声明被解释为函数声明,以指针(表示为数组)作为其参数。为了更清楚地说明这一点,我将删除函数声明中冗余的一些括号:

std::ifstream strings(std::string argv[1]);

,根据数组/指针混淆的古老规则,它相当于

std::ifstream strings(std::string * argv);

与错误消息中提到的类型匹配。

从c++ 11开始,你可以使用大括号初始化来解决这个问题:

std::ifstream strings{std::string(argv[1])};
                     ^                    ^

在历史方言中,你需要更多的冗长:

std::ifstream strings = std::ifstream(std::string(argv[1]).c_str());

注意,在c++ 11之前,你不能直接将std::string传递给构造函数,而需要c_str()来获得C风格的字符串。

正如您所说,您可以简单地将argv[1]作为任何c++方言的参数传递,从而完全避免了麻烦的解析。