Уникальный указатель на интерфейс шаблона - PullRequest
0 голосов
/ 21 мая 2018

Ради простоты я свел свою проблему к простому примеру.У меня есть базовый класс:

template<typename T>
class Base {
    virtual T getParameter(T&) = 0;
};

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

template<typename T>
class Der : public Base<T> {
public:
    static std::unique_ptr<Der> getInstance() {
        return std::make_unique<Der<std::string>>();
    }
    T getParameter(T& param) override {
        return param;
    }
};

Теперь я хотел бы передать объекты производного класса, используя unique_ptr, который содержит интерфейс,т.е.:

template<typename T>
void someFun(std::unique_ptr<Base<T>>&& ptr) {
//do sth with ptr
}

по телефону:

someFun(Der<std::string>::getInstance());

Ошибка:

test.cpp:26:44: error: no matching function for call to ‘someFun(std::unique_ptr<Der<std::__cxx11::basic_string<char> >, std::default_delete<Der<std::__cxx11::basic_string<char> > > >)’
     someFun(Der<std::string>::getInstance());
                                            ^
test.cpp:21:6: note: candidate: template<class T> void someFun(std::unique_ptr<Base<T> >&&)
 void someFun(std::unique_ptr<Base<T>>&& ptr) {
      ^~~~~~~
test.cpp:21:6: note:   template argument deduction/substitution failed:
test.cpp:26:44: note:   mismatched types ‘Base<T>’ and ‘Der<std::__cxx11::basic_string<char> >’
     someFun(Der<std::string>::getInstance());

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

В первый раз я отвечу на свой вопрос, решение - вернуть уникальный ptr в класс Base not Derived:

static std::unique_ptr<Base<T>> getInstance() {
    return std::make_unique<Der<std::string>>();
}

ранее я возвратил static std::unique_ptr<Der>, и компилятор предположил, что я не хочуRef мой объект, используя интерфейс.Может быть, это поможет любому, кто имеет такую ​​же проблему.

0 голосов
/ 21 мая 2018

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

Вы по-прежнему можете применять наследование от Base, используя std::is_base_of<>, если вы боитесь набирать утку на предмете, не связанном с случайностью.

#include <memory>
#include <typer_traits>

template<typename T>
class Base {
public:
    using param_t = T;
    virtual T getParameter(T&) = 0;
};

template<typename T>
class Der : public Base<T> {
public:
    static std::unique_ptr<Der> getInstance() {
        return std::make_unique<Der<std::string>>();
    }
    T getParameter(T& param) override {
        return param;
    }
};

template<typename DerivT>
void someFun(std::unique_ptr<DerivT> deriv_ptr) {
    using T = typename DerivT::param_t;
    // Just to be safe
    static_assert(std::is_base_of<Base<T>, DerivT>::value, "");

    // If you REALLY care about only having a base pointer:
    std::unique_ptr<Base<T>> ptr(deriv_ptr.release());    

    //do stuff.
}

void foo() {
    someFun(Der<std::string>::getInstance());
}

Вы также сможетечто-нибудь помешайте с enable_if, если вы действительно хотите обрабатывать различные перегрузки someFun().Тем не менее, я считаю, что static_assert() намного чище, поэтому я использовал бы его, если не было необходимости.

...