【问题标题】:Why is the construction of istreams forbidden?为什么禁止构建 istream?
【发布时间】:2019-11-30 18:11:51
【问题描述】:

这里有一些代码:

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <istream>
#include <ostream>

class A {
    int *m;
    std::istream in;
    A(int *m, std::string file): m{m}, in{std::ifstream{file}} { foo(); }
public:
    A(int *m): m{m}, in{std::cin} { foo(); }
    void foo() {}
};

int main() {
    return 0;
}

当我尝试做g++ -std=c++14 main.cc 时,我最终得到的是:

$ g++ -std=c++14 main.cc
main.cc: In constructor ‘A::A(int*, std::__cxx11::string)’:
main.cc:11:62: error: ‘std::basic_istream<_CharT, _Traits>::basic_istream(std::basic_istream<_CharT, _Traits>&&) [with _CharT = char; _Traits = std::char_traits<char>]’ is protected within this context
     A(int *m, std::string file): m{m}, in{std::ifstream{file}} { foo(); }
                                                              ^
In file included from /usr/include/c++/7/iostream:40:0,
                 from main.cc:1:
/usr/include/c++/7/istream:613:7: note: declared protected here
       basic_istream(basic_istream&& __rhs)
       ^~~~~~~~~~~~~
main.cc: In constructor ‘A::A(int*)’:
main.cc:13:33: error: ‘std::basic_istream<_CharT, _Traits>::basic_istream(const std::basic_istream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’ is protected within this context
     A(int *m): m{m}, in{std::cin} { foo(); }
                                 ^
In file included from /usr/include/c++/7/iostream:40:0,
                 from main.cc:1:
/usr/include/c++/7/istream:611:7: note: declared protected here
       basic_istream(const basic_istream&) = delete;
       ^~~~~~~~~~~~~
main.cc:13:33: error: use of deleted function ‘std::basic_istream<_CharT, _Traits>::basic_istream(const std::basic_istream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’
     A(int *m): m{m}, in{std::cin} { foo(); }
                                 ^
In file included from /usr/include/c++/7/iostream:40:0,
                 from main.cc:1:
/usr/include/c++/7/istream:611:7: note: declared here
       basic_istream(const basic_istream&) = delete;
       ^~~~~~~~~~~~~

我知道不可能对istream 进行任何类型的分配,但我至少认为我可以构造一个,就像ifstream 和其他人一样。我在这里做错了什么?

编辑:即使将in 设为参考也会导致:

main.cc: In constructor ‘A::A(int*, std::__cxx11::string)’:
main.cc:11:62: error: cannot bind non-const lvalue reference of type ‘std::istream& {aka std::basic_istream<char>&}’ to an rvalue of type ‘std::basic_istream<char>’
     A(int *m, std::string file): m{m}, in{std::ifstream{file}} { foo(); }
                                                              ^

这是为什么?

【问题讨论】:

  • 您不能复制cin,但可以存储对它的引用。只需将in 作为参考,它应该可以解决它。但是,看到您的编辑,您将无法将临时引用绑定到非常量引用。
  • @iz_ 好的,这样做:const std::istream &amp;in; 使其编译,但我通过使其成为const 会失去任何东西吗?因为我们永远不会分配给istream,不是吗?
  • 通过从流中读取,你正在改变它。 const 将使其无法读取流。
  • @iz_ 有没有优雅的解决方案?您如何从中读取信息并将其作为成员(拥有它)?
  • 以下核桃的解决方案对我来说看起来不错。

标签: c++


【解决方案1】:

您需要确定A 是否应该拥有该流。

如果它确实拥有流,那么您不能传递它std::cin,您需要直接存储ifstreamunique_ptr&lt;istream&gt; 而不是istream,因为您希望允许派生类型,例如@987654326 @。

如果它是非拥有的,那么你不能在构造函数中创建实例。相反,调用者需要创建和拥有流并将对它的引用传递给您的构造函数。为此,您应该保存引用 istream&amp; 而不是 istreamstd::reference_wrapper&lt;istream&gt;,如果您想允许为类赋值,或者是原始(非拥有)指针 istream*

如果你想同时允许,你可以创建一个只接受引用的基类,然后你可以创建一个派生类来额外构造和拥有流。然后,在需要时,您可以根据是否应该拥有它来构造派生类或基类类型。

class A {
    std::istream& in;
public:
    A() : A(std::cin) { }
    A(std::istream& in): in(in) { }
};

class B : public A {
    std::ifstream ifs;
public:
    B(std::string file) : A(ifs), ifs(file) { }
};

也许您想通过给A 一个虚拟析构函数和虚拟成员函数来使类具有多态性,以防您想使用具有运行时多态性的两个类。

或者,您可以为一个拥有和一个非拥有版本的类模板。或者您可以使用std::variant 作为成员,它可以保存拥有或非拥有类型。哪种解决方案最适合您,取决于您打算如何使用该类。

【讨论】:

  • 在我的特殊情况下,我没有任何继承或多态性。 A 是否有可能以某种方式从in 中读取,其中in 可以是std::cin 或动态构建的ifstream?现在唯一可以解决这个问题的似乎是将ifs 作为A 的附加成员,然后在构造in 时,我们使用in(ifs)。不过,这看起来确实有些多余。
  • @herophant 是的,你当然可以合并这两个类并拥有一个引用和非引用成员,或者你可以使用std::variant&lt;std::unique_ptr&lt;std::istream&gt;, std::ifstream&gt;,但使用std::variant 有点棘手,可能不值得。类模板将使类型之间的切换也很容易。同样,我不知道具体的要求是什么。
猜你喜欢
  • 2013-09-12
  • 2011-12-15
  • 2022-01-15
  • 2015-10-07
  • 2016-06-05
  • 2022-01-07
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多