C++ 为什么禁止建造峡湾?

C++ 为什么禁止建造峡湾?,c++,C++,下面是一些代码: #包括 #包括 #包括 #包括 #包括 #包括 甲级{ int*m; std::istream in; (int*m,std::string file):m{m},在{std::ifstream{file}}{foo();} 公众: A(int*m):m{m},在{std::cin}{foo();} void foo(){} }; int main(){ 返回0; } 当我尝试执行g++-std=c++14 main.cc时,最终得到的结果是: $ g++ -std=c++1

下面是一些代码:

#包括
#包括
#包括
#包括
#包括
#包括
甲级{
int*m;
std::istream in;
(int*m,std::string file):m{m},在{std::ifstream{file}}{foo();}
公众:
A(int*m):m{m},在{std::cin}{foo();}
void foo(){}
};
int main(){
返回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;
       ^~~~~~~~~~~~~

这是为什么?

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

如果它确实拥有流,那么您不能传递它
std::cin
,您需要直接存储
ifstream
,或者存储
unique\u ptr
,而不是
istream
,因为您希望允许派生类型,例如
ifstream

如果它是非拥有的,则无法在构造函数中创建实例。相反,调用方需要创建并拥有流,并将对它的引用传递给构造函数。为此,如果要允许类的赋值或原始(非拥有)指针
istream*
,则应保存引用
istream&
,而不是
istream
std::reference\u wrapper

如果希望两者都允许,可以创建一个只接受引用的基类,然后创建一个派生类来额外构造和拥有流。然后,无论何时需要,您都可以根据是否应该拥有派生类或基类类型来构造它

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) { }
};
如果要使用具有运行时多态性的两个类,可能需要通过提供一个虚拟析构函数和虚拟成员函数使类具有多态性


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

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

如果它确实拥有流,那么您不能传递它
std::cin
,您需要直接存储
ifstream
,或者存储
unique\u ptr
,而不是
istream
,因为您希望允许派生类型,例如
ifstream

如果它是非拥有的,则无法在构造函数中创建实例。相反,调用方需要创建并拥有流,并将对它的引用传递给构造函数。为此,如果要允许类的赋值或原始(非拥有)指针
istream*
,则应保存引用
istream&
,而不是
istream
std::reference\u wrapper

如果希望两者都允许,可以创建一个只接受引用的基类,然后创建一个派生类来额外构造和拥有流。然后,无论何时需要,您都可以根据是否应该拥有派生类或基类类型来构造它

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) { }
};
如果要使用具有运行时多态性的两个类,可能需要通过提供一个虚拟析构函数和虚拟成员函数使类具有多态性


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

您不能复制
cin
,但可以存储对它的引用。只需将
中的
作为一个引用,它就会解决这个问题。但是,看到您的编辑,将临时引用绑定到非常量引用时会出现问题。@iz_uu;Ok,执行此操作:
const std::istream&in
使其可编译,但使其
常量
会丢失任何东西吗?因为我们永远不会分配给
istream
,这不是很好吗?从流中读取,就是对它进行变异
const
将使其无法读取流。@iz_u有一个优雅的解决方案吗?你如何阅读它,并将其作为成员(拥有它)?胡桃木下面的解决方案在我看来很好。你不能复制
cin
,但你可以存储对它的引用。只需将
中的
作为一个引用,它就会解决这个问题。但是,看到您的编辑,将临时引用绑定到非常量引用时会出现问题。@iz_uu;Ok,执行此操作:
const std::istream&in
使其可编译,但使其
常量
会丢失任何东西吗?因为我们永远不会分配给
istream
,这不是很好吗?从流中读取,就是对它进行变异
const
将使其无法读取流。@iz_u有一个优雅的解决方案吗?你如何能从中阅读,并将其作为一个成员(拥有它)?胡桃木下面的解决方案对我来说很好。在我的特殊情况下,我没有任何继承或多态性。
A
是否可能以某种方式从
中的
读取,其中
中的
可以是
std::cin
或动态构造的
ifstream
?目前唯一可能解决这个问题的方法似乎是将
ifs
作为
A
的附加成员,然后在
中构造
时,我们在(ifs)
中执行
。这看起来有点多余。@herophant是的,您当然可以合并这两个类,并拥有一个引用和非引用成员,或者您可以使用
std::variant
,但是使用
std::variant
有点棘手,可能不值得。类模板可以使类型之间的切换变得很容易。同样,我不知道具体的需求是什么。在我的特殊情况下,我没有任何继承或多态性。
A
是否可能以某种方式从
中的
读取,其中
中的
可以是
s