c ++ r-значение подвижного типа в конструкторе - PullRequest
3 голосов
/ 21 декабря 2011

Я использую C ++ 11 и пытаюсь создать класс, которому принадлежит подвижный тип, например:

class foo {
    std::istream input;

public:
    foo(std::istream && in): input(in) { }
};

И затем создать экземпляр объекта:

foo var1(std::ifstream("/tmp/something"));

Но компилятор всегда жалуется, что я вызываю удаленный конструктор. Это вообще возможно?

clang++ -stdlib=libc++ -std=c++0x foo.cpp 
foo.cpp:7:30: error: call to deleted constructor of 'std::istream' (aka 'basic_istream<char>')
    foo(std::istream && in): input(in) { }
                             ^     ~~
/usr/bin/../lib/c++/v1/istream:1740:23: note: function has been explicitly marked deleted here
extern template class basic_istream<char>;
                      ^
1 error generated.

Ответы [ 4 ]

9 голосов
/ 21 декабря 2011

К сожалению, вы не можете скопировать (или даже переместить) абстрактный тип потока std::istream. Вы можете хранить их по ссылке, но это не похоже на то, что хочет сделать ваш код.

Когда вы передаете std::ifstream, я предполагаю, что это тип потока, с которым вы действительно хотите иметь дело. В отличие от std::istream, std::ifstream является конкретным типом. И этот тип является подвижным, но не копируемым.

Ответ hmjd, и то, что вы отметили правильно, - лучший способ закодировать это:

#include <fstream>

class foo
{
    std::ifstream input;
public:
    foo(std::ifstream&& in): input(std::move(in)) { }
};

Объяснение: Конструктор foo будет принимать только значение std::ifstream s, что является правильным. Но как только вы попадете внутрь этого конструктора, переменная in больше не будет значением r (это значение l). И поэтому вам нужно привести его обратно к r-значению (используя std::move), чтобы переместить конструкцию элемента данных input.

Это тот же шаблон, который вы использовали бы с любым типом только для перемещения (stringstream, unique_ptr, future, unique_lock и т. Д.).

3 голосов
/ 21 декабря 2011

Как насчет решения, которое использует unique_ptr:

#include <iostream>
#include <fstream>
#include <memory>

using namespace std;

class foo {
    unique_ptr<ifstream> input;

public:
    foo( unique_ptr<std::ifstream>&& in ): input( std::move(in) ) { }
};

int main()
{
    std::unique_ptr<ifstream> myStream( new ifstream( "something" ) );
    foo f( std::move( myStream ) );
    return 0;
}

Это можно улучшить, используя свернутый вручную шаблон make_unique (см .: suttersmill gotw # 102

2 голосов
/ 21 декабря 2011

Я думаю, что важная строка в вопросе такова:

foo var1(std::ifstream("/tmp/something"));

Спрашивающий просто хочет, чтобы это или что-то подобное «просто работало», и на самом деле спрашивающему не нужны движения или что-то в этом роде. (Это правильно?)

Вот ответ:

#include <fstream>
#include <iostream>
using namespace std;
template <class T>
class foo {
public:
        typedef typename std :: remove_reference<T> :: type value_type;
        value_type input;
        template <class ... Args>
        foo(Args... args): input(args...) {}
};

int main() {
        foo<std::ifstream> var1("/tmp/something");
}

Требуется ли вам версия, которая принимает только типы, которые можно преобразовать в istream? Вы можете включить других членов типа istream& и инициализировать это с input. Это заставит шаблон использовать только подходящие типы.

1 голос
/ 21 декабря 2011

Я думаю, вы должны забыть о move и &&.Вы не можете легко создать istream - это очень простой тип, который не имеет много подходящих конструкторов . Ошибка говорит вам, что istream не может быть перемещено.

Возможно, вам придется явно контролировать время жизни самостоятельно, и foo сохранит ссылку.

class foo {
public:
    std::istream &input;

    foo(std::istream& in): input(in) { }
};

std::ifstream a_suitable_variable ("/tmp/something");
foo(a_suitable_variable);

Другой вариант - просто передать имя файла конструктору.

class foo {
public:
    std::ifstream input; // NOT a reference this time

    foo(string s): input(s) { }
};
foo("/tmp/something");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...