Проблема в том, что basic_istream
(база basic_ifstream
, из которых шаблон ifstream
является экземпляром) фактически наследуется от basic_ios
, а basic_ios
имеет удаленный конструктор перемещения (в дополнение к защищенному конструктору по умолчанию).
(Причина виртуального наследования заключается в том, что в дереве наследования fstream
есть ромб, который наследуется от ifstream
и ofstream
.)
Это малоизвестный и / или легко забываемый факт, что самый производный конструктор класса напрямую вызывает свои (унаследованные) виртуальные базовые конструкторы, и если он не делает этого явно в base-or-member-init-list тогда будет вызван конструктор default виртуальной базы. Однако (и это еще более непонятно) для конструктора копирования / перемещения, неявно определенного или объявленного по умолчанию, выбранный конструктор виртуального базового класса не конструктор по умолчанию, но соответствует конструктор копирования / перемещения; если он удален или недоступен, конструктор копирования / перемещения самого производного класса будет определен как удаленный.
Вот пример (который работает еще в 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
(Здесь B
соответствует basic_ios
, C
- ifstream
и D
- вашему BinFile
; basic_istream
не требуется для демонстрации.)
Если свернутый вручную Конструктор копирования D не закомментирован, программа скомпилируется, но она будет вызывать B::B()
, , а не B::B(int)
. Это одна из причин, почему плохая идея наследовать от классов, которые явно не дали вам разрешения на это; вы не можете вызывать тот же виртуальный базовый конструктор, который был бы вызван конструктором класса, от которого вы унаследовали, если бы этот конструктор был вызван как конструктор класса с наибольшим производным.
Что вы можете сделать, Я считаю, что рукописный конструктор перемещения должен работать, поскольку и в libstdc ++, и в libcxx конструктор перемещения basic_ifstream
не вызывает конструктор не по умолчанию basic_ios
(есть один из указателя basic_streambuf
), но вместо этого инициализирует его в теле конструктора (похоже, это то, что говорит [ifstream.cons] / 4 ). Стоит прочитать Расширение стандартной библиотеки C ++ с помощью наследования? для других потенциальных ошибок.