Единый конструктор копирования и перемещения шаблонного класса - PullRequest
0 голосов
/ 20 марта 2019

Предположим, у меня есть шаблонный класс DataProcessor, который содержит интеллектуальный указатель на обработанные данные с оператором * и оператором ->:

template <class DataPointer>
class DataProcessor
{
    public:

        //it is not clear how to implement the constructor
        //DataProcessor(DataPointer p) : pData(p) {};

        void Process() { /* do something with *pData */ };

    private:

        DataPointer pData;
}

Как реализовать конструктор, чтобы DataProcessor работал с обоими стандартными переменными:: unique_ptr (конструктор должен принять его с помощью && и переместить его) и std :: shared_ptr (конструктор должен принять его с помощью & и скопировать его)?Возможно ли иметь какой-то унифицированный конструктор?

На самом деле у меня есть класс, который содержит умные Win32-дескрипторы UniqueHandle и SharedHandle, которые имеют похожую семантику, такую ​​как std :: unique_ptr и std :: shared_ptr.Так что это общий вопрос о том, как реализовать такой сценарий.

1 Ответ

2 голосов
/ 20 марта 2019

Ваш выбор в основном таков:

  1. Примите параметр по значению:

    DataProcessor(DataPointer p) : pData(std::move(p)) {}
    

    Если DataPointer только для перемещения, то у пользователя будетчтобы вызвать его через std::move, который будет перемещать-конструировать p, который затем используется для перемещения-построения pData.Если он является копируемым, то p будет создан для копирования / перемещения на основе того, как пользователь передает значение.Оттуда будет перемещена конструкция pData.

    Обратите внимание, что в этой версии добавлена ​​дополнительная операция перемещения.

  2. Возьмите параметр по ссылке rvalue, всегда:

    DataProcessor(DataPointer &&p) : pData(std::move(p)) {}
    

    В этом случае, если DataPointer не только для перемещения, и пользователь хочет передать lvalue, пользователь должен явно скопировать значение во временное хранилище, используемое для инициализации p.Это будет выглядеть примерно так:

    DataProcessor<shared_ptr<T>> dp(shared_ptr{sp});
    

    Где sp - это существующий shared_ptr, из которого вы хотите скопировать.Это делает только одно перемещение, когда задан объект для перемещения, но выполняет копирование + перемещение при копировании.

  3. Написать две функции, используя SFINAE для удаления версии копирования, если DataPointerбез копируемого.Эта версия имеет преимущество в том, что не делает никаких дополнительных ходов:

DataProcessor(DataPointer &&p) : pData(std::move(p)) {}
template<typename T = DataPointer>
DataProcessor(std::enable_if_t<std::is_copy_constructible_v<T>, const T&> p)
        : pData(p) {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...