Является ли конструктор перемещения ifsteam неявно удаленным?

У меня есть следующий простой класс:

class Source
{
public:
    Source() = default;
    Source(Source const&) = delete;
    Source(Source&&) = default;

    explicit Source(std::string const& fileName)
     : inputStream(fileName), path_(fileName)
    {}

    ~Source() = default;

    auto path() const -> std::string
    {
        return this->path_;
    }

    std::ifstream inputStream;
private:
    std::string path_;
};

auto main(int argc, char* argv[]) -> int
{
    Source source(Source("test.txt"));
    cout << source.path() << "\n";

    return 0;
}

Согласно cppreference ifstream имеет конструктор move, но когда я пытаюсь скомпилировать его с помощью MinGW 4.7.2, я получаю следующую ошибку:

..\src\main.cpp: 32: 46: ошибка: использование удаленной функции 'cy:: Source:: Source (cy:: Source &)' В файле, включенном в.. \src\main.cpp: 10: 0: source.hpp: 28: 5: note: 'cy:: Source:: Source (cy:: Source &)' неявно удаляется, поскольку определение по умолчанию будет плохо сформировано: source.hpp: 28: 5: ошибка: использование удаленная функция 'std:: basic_ifstream:: basic_ifstream (const станд:: basic_ifstream &) "C:\MinGW\бен../Library/GCC/mingw32/4.7.2/включить/С++/fstream: 420: 11: note: 'std:: basic_ifstream:: basic_ifstream (const std:: basic_ifstream &) 'неявно удаляется, поскольку значение по умолчанию определение будет плохо сформировано: C:\MinGW\бен../Library/GCC/mingw32/4.7.2/включить/С++/fstream: 420: 11: Ошибка: использование удаленной функции" Станд:: basic_istream:: basic_istream (Const станд:: basic_istream &)

Я что-то делаю неправильно? Или документация cppreference неточна? Или у GCC 4.7.2 есть ошибка?

Ответ 1

Оказывается, что стандартная реализация библиотеки GCC еще не реализовала операцию перемещения и свопинга для классов потоков. См. здесь для подробностей о текущем состоянии функций С++ 11 в стандартной библиотеке gcc.

Спасибо Jesse Good за предоставленную информацию и ссылку.

Ответ 2

Я понимаю, что этот ответ немного запоздал, но чтобы дать невозмутимую семантику перемещения класса, вы могли бы написать очень простой класс-оболочку. Например:

#include <memory>



template <typename T>
class swap_wrapper
{
    //! internal buffer to hold object (on heap)
    std::unique_ptr<T> p_obj;
public:
    //! allows any of objects constructors to be called directly
    template <typename... Args>
    explicit swap_wrapper(Args&&... args)
        :   p_obj(
                     new T( std::forward<Args>(args)... )
                     ) {    }

    //! swaps pointer value of T object is unchanged therefore this 
    //! function puts no requirement on base class.

    //! note p_obj is left as a nullptr so dereferencing will cause
    //! undefined behaviour.
    swap_wrapper (swap_wrapper &&other) noexcept
        : p_obj(nullptr)
    {
        swap(other);
    }

    //! swaps pointer like above,
    //! T object is not touched; just the pointer.
    swap_wrapper &operator = (swap_wrapper &&other) noexcept
    {
        swap(other);
        return *this;
    }

    //! uses swap member function of std:unique_ptr
    void swap(swap_wrapper &other) noexcept
    {
        std::swap(p_obj, other.p_obj);
    }

    //! operators to allow access to stream
    T& operator *() { return *p_obj; }
    T const& operator *() const { return *p_obj; }

    T * operator ->() { return p_obj.get(); }
    T const * operator ->() const { return p_obj.get(); }

};


//! overload of default swap (calls member function swap)
template <typename S>
inline void swap(swap_wrapper<S> &one, swap_wrapper<S> &two) noexcept
{ one.swap(two); }

Затем эту оболочку можно вернуть из функций, переданных как параметр rvalue и т.д.