首页 > 解决方案 > 指向模板接口的唯一指针

问题描述

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

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());

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

解决方案


我认为解决这个问题的最简单方法是在派生类型上创建Tin Base、模板的别名,并使用它而不是依赖模板推导。

如果您害怕在不相关的东西中意外键入鸭子,您仍然可以Base通过 using强制继承。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()方式更清洁,所以除非必要,否则我会使用它。


推荐阅读