指向模板界面的唯一指针

时间:2018-05-21 15:24:18

标签: c++ c++14 unique-ptr

为简单起见,我将问题简化为简单的例子。我有基类:

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 :(得分:1)

我认为解决此问题的最简单方法是在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()方式更清晰,所以除非必要,否则我会使用它。

答案 1 :(得分:0)

我第一次回答自己的问题,解决方法是将基础非衍生类返回给唯一的ptr:

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

之前我返回static std::unique_ptr<Der>并且编译器假定我不想使用接口来引用我的对象。也许它会帮助任何人有同样的问题。