The issue is that basic_istream
(a base of basic_ifstream
, of which template ifstream
is an instantiation) virtually inherits from basic_ios
, and basic_ios
has a deleted move constructor (in addition to a protected default constructor).
(The reason for virtual inheritance is that there is a diamond in the inheritance tree of fstream
, which inherits from ifstream
and ofstream
.)
It's a little known and/or easily forgotten fact that the most derived class constructor calls its (inherited) virtual base constructors directly, and if it does not do so explicitly in the base-or-member-init-list then the virtual base's default constructor will be called. However (and this is even more obscure), for a copy/move constructor implicitly defined or declared as defaulted, the virtual base class constructor selected is not the default constructor but is the corresponding copy/move constructor; if this is deleted or inaccessible the most derived class copy/move constructor will be defined as deleted.
Here's an example (that works as far back as C++98):
struct B { B(); B(int); private: B(B const&); };
struct C : virtual B { C(C const&) : B(42) {} };
struct D : C {
// D(D const& d) : C(d) {}
};
D f(D const& d) { return d; } // fails
(Here B
corresponds to basic_ios
, C
to ifstream
and D
to your BinFile
; basic_istream
is unnecessary for the demonstration.)
If the hand-rolled copy constructor of D is uncommented, the program will compile but it will call B::B()
, not B::B(int)
. This is one reason why it is a bad idea to inherit from classes that have not explicitly given you permission to do so; you may not be calling the same virtual base constructor that would be called by the constructor of the class you are inheriting from if that constructor were called as a most-derived class constructor.
As to what you can do, I believe that a hand-written move constructor should work, since in both libstdc++ and libcxx the move constructor of basic_ifstream
does not call a non-default constructor of basic_ios
(there is one, from a basic_streambuf
pointer), but instead initializes it in the constructor body (it looks like this is what [ifstream.cons]/4 is saying). It would be worth reading Extending the C++ Standard Library by inheritance? for other potential gotchas.
std::ifstream&
as one of its arguments. Inheritance seems like overkill here. – SardineBinFile(BinFile&& other) : std::ifstream(std::move(other)) {}
Not sure how this is different from ` = default;` – Crooks