为什么这个无法编译?

4

当我尝试使用第一种形式声明iss时,g++会报错:"error: no match for 'operator>>' in 'iss >> s'"。但是这两种不同的声明方式不是做同样的事情吗?

#include <iostream>
#include <sstream>
#include <string>


int main() {
    const char *buf = "hello world";
    std::string ss(buf);
    //std::istringstream iss(std::string(buf)); // this doesn't work
    std::istringstream iss(ss); // but this does
    std::string s;
    iss >> s;
}
5个回答

11

这被称为C++中最令人头疼的解析:对您来说看起来像实例声明的内容实际上在编译器中看起来像函数声明。

std::string name(); //function declaration
std::string name;  //object declaration with default constructor

std::stringstream ss(std::string(buf));  //function declaration
std::stringstream ss(std::string buf);  //another function declaration
std::stringstream ss(std::string);  //also a function declaration
std::stringstream ss(std::string());  //ditto, argument names are optional

std::stringstream ss((std::string(buf))); //object declaration

注意最后一个例子中额外的括号。这些括号在函数声明中是不合法的。

第一个默认构造函数的例子是众所周知的。第二个例子中增加了不清晰性的是,C++ 中参数名周围的括号是合法但可选的。例如,你可以像这样定义一个函数:

void foo(int (bar))
{}

基本上,每当构造函数的所有参数都是从接受0个或1个参数的构造函数调用中得到的临时对象时,就会遇到这个问题,解决方案是在其中一个参数周围添加额外的括号。


8
这是因为istringstream需要一个字符串的常量引用作为参数,所以你不能直接这样写:
std::istringstream iss(std::string(buf));

实际上你是可以的,但这意味着你正在声明一个函数iss,它接受一个std::string并返回std::istringstream。同样地,你也可以这样写:

std::istringstream iss(std::string buf);

这是一些相当高级的 C++ 技术。


0

我猜对于std::string(char*)返回的类型有些混淆,因为这个:

  std::istringstream iss((std::string)std::string(buf));

运作正常。


这是因为没有强制类型转换,它声明了一个名为iss的函数,该函数接受一个std::string并返回一个std::istringstream(参数名称周围的括号是可选的)。由于强制类型转换不能出现在声明函数参数中,因此这必须明确是对接受std::stringistringstream的构造函数)的某个东西的调用 - UncleBens

-1
构造一个从字符串创建istream的第一个参数需要是:const string & str,而这个并没有被创建:
    std::string(buf)

虽然以下代码说明了这一点,但它会泄漏内存,所以不要真的使用它。

    std::istringstream iss(*new std::string(buf));

-5

你不需要使用 namespace std; 吗?


不,他已经给 std 命名空间中的所有内容都加了前缀。 - Paul Tomblin
好的,对不起!如果我错了,你不需要把我投出去。我犯了一个错误,每个人都会犯错。给个机会吧! - Jab
3
这不是个人私仇,只是一个指示,表明你的答案是错误的,这也是投票的一部分。 - Alex Rozanski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接