шаблонный конструктор или конструктор шаблонной копии - PullRequest
3 голосов
/ 12 декабря 2010

У меня есть класс с шаблонным конструктором для неявного преобразования перемещения, однако этот конструктор НЕ должен использоваться для класса (который должен быть только копируемым) Однако компилятор всегда пытается использовать шаблонный конструктор вместо обычного конструктора копирования.

например. При этом я получаю следующие ошибки компилятора, ссылка . (Вы можете просто скопировать и вставить этот код, если хотите попробовать)

struct implementation{};
class my_class
{
 my_class(my_class&&); // delete move-constructor... OUCH... COMPILER ERROR
public:
 my_class(){}
 my_class(const my_class& other) : impl_(other.impl_){}

 template<typename T>
 my_class(T&& impl) : impl_(std::make_shared<T>(std::move(impl))){} // Still tries to use this...

private:
 std::shared_ptr<implementation> impl_;
};

class other_class
{
public:
 my_class foo()
 { 
       return instance_; // Wants to use move-constructor???
 }
private:
 my_class instance_;
};

У кого-нибудь есть идеи, как решить это правильно?

Ответы [ 2 ]

4 голосов
/ 12 декабря 2010

Хорошо, вот мой капитальный ремонт my_class:

class my_class
{
public:
    my_class() {}
    my_class(my_class&& that) : impl_(std::move(that.impl_)) {}

    template <typename T> my_class(T&& impl,
    typename std::enable_if<
        std::is_base_of<
            implementation,
            typename std::remove_reference<T>::type
        >::value,
        void
    >::type* dummy = 0
    ) : impl_(std::make_shared<T>(std::forward<T>(impl))) {}

    template <typename T>
    typename std::enable_if<
        std::is_base_of<
            implementation,
            typename std::remove_reference<T>::type
        >::value,
        my_class&
    >::type
    operator=(T&& impl)
    {
        std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_);
        return *this;
    }

private:
    std::shared_ptr<implementation> impl_;
};

Как предположили другие, это работает для ссылок lvalue и rvalue с использованием std::forward вместо std::move. remove_reference необходим, поскольку для ссылок lvalue T является ссылкой, а derived& не является производным от base, а derived (обратите внимание на ссылку).

2 голосов
/ 12 декабря 2010

Это может никогда не сработать:

template<typename T>
my_class(typename std::enable_if<std::is_base_of<implementation, derived_1>::value, T&&>::type impl) : impl_(std::make_shared<T>(std::move(impl)))  {}

template <typename T> 
my_class& operator= (typename std::enable_if<std::is_rvalue_reference<T&&>::value && !std::is_same<T, my_class>::value, T&&>::type impl)

Причина в том, что вы используете T только в не выведенных контекстах.Проще говоря, компилятор не может вывести T, если аргумент, из которого он должен был вывести его, имеет форму Anything<T>::type.

Итак, если вы хотите использовать enable_if в операторе присваивания, вы помещаете еговозвращаемое значение:

template <class T>
typename enable_if<..., T&>::type operator=(const T&);

в случае конструктора преобразования (должен работать и для перемещения), вы добавляете фиктивный параметр со значением по умолчанию:

template <class T>
MyClass(const T&, typename enable_if<..., void>::type* =0);

FredOverflow уже дал вамправильный оператор присваивания.

Кстати, вам не нужно ограничивать его ссылками rvalue, если вы используете std::forward вместо std::move.Смотрите здесь .Это даст вам (скопируйте и вставьте из FredOverflow):

template <typename T>
typename std::enable_if<std::is_base_of<implementation, T>::value, my_class&>::type
operator=(T&& impl)
{
    std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_);
    return *this;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...