【问题标题】:Unique pointer to template interface指向模板接口的唯一指针
【发布时间】:2018-05-21 15:24:17
【问题描述】:

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

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++14 unique-ptr


    【解决方案1】:

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

    如果您害怕在不相关的内容中意外键入鸭子,您仍然可以使用 std::is_base_of&lt;&gt; 强制从 Base 继承。

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

    如果你真的想处理someFun() 的不同重载,你也可以用enable_if 来搞定一些事情。不过,我发现static_assert() 的方式更干净,所以除非必要,否则我会使用它。

    【讨论】:

    • 你只是把整个参数改成了T,我知道,但我需要Base>
    • @user3655463 在 someFun() 的上下文中,T 实际上是Derived&lt;param_t&gt;,我可以理解混乱,我已经修复了示例
    【解决方案2】:

    第一次我会回答我自己的问题,解决方案是将唯一的 ptr 返回到 Base not Derived 类:

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

    之前我返回了static std::unique_ptr&lt;Der&gt;,编译器假设我不想使用接口引用我的对象。也许它会帮助任何有同样问题的人。

    【讨论】:

      猜你喜欢
      • 2013-04-28
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      • 2014-07-29
      • 2015-04-26
      • 1970-01-01
      相关资源
      最近更新 更多