基于智能指针的*内侧类型,对模板进行特殊化。

问题描述 投票:0回答:1

我有一个类,它封装了一个通用的 "智能指针"(可以是 unique_ptr, shared_ptr等)。)

我试图将构造函数特殊化,以便调用适当的 make_unique, make_shared等,但我不知道正确的语法。

下面是我的想法(实况转播):

template <class SmartPtr>
struct Holder {

    typedef typename SmartPtr::element_type value_type;

    Holder()
        : m_ptr(new value_type) // The fallback implementation calls 'new' directly.
    {}

private:

    SmartPtr m_ptr;

};

// THIS DOES NOT COMPILE
// Notice the "T" type, which is not declared anywhere.
// How do I declare this sort of thing properly?
template<>
Holder<shared_ptr<T>>::Holder
    : m_ptr(make_shared<T>())
{}

我想基于智能指针进行专门化 但我也需要访问智能指针管理的底层类型。

这是C++14,但我对其他标准的想法也很感兴趣。


EDIT: 一些类似的问题,但在这种情况下并不完全适用(或者即使适用,我也不清楚所需的转换)。

c++ templates c++14 template-specialization
1个回答
1
投票

不考虑语法错误,你的代码不能编译的原因是,你不能部分特殊化函数模板,你只能部分特殊化类模板。但是,你可以重载函数。使用函数重载来解决这个问题,一点也不容易。我在下面详细介绍了两种技术,你可以用这两种技术来解决你的问题,其中第二种技术是利用部分模板特化。

首先,假设你有一个C++17编译器,你可以使用 if constexpr 和模板编程来获得理想的效果。

template <class SmartPtr>
struct Holder {

    //this is a nested helper struct, which will allow us to deduce at compile-time
    //    whether SmartPtr is a std::unique_ptr or not, using function overloading
    template<typename T>
    struct is_unique_ptr{
        template<typename TT>
        constexpr static std::true_type test(std::unique_ptr<TT>*);

        constexpr static std::false_type test(...);

        using type = decltype(test(std::declval<T*>()));
        constexpr static bool value = type::value;
    };


    //this is a nested helper struct, which will allow us to deduce at compile-time
    //    whether SmartPtr is a std::shared_ptr or not, using function overloading
    template<typename T>
    struct is_shared_ptr{
        template<typename TT>
        constexpr static std::true_type test(std::shared_ptr<TT>*);

        constexpr static std::false_type test(...);

        using type = decltype(test(std::declval<T*>()));
        constexpr static bool value = type::value;
    };

    typedef typename SmartPtr::element_type value_type;

    //default constructor will conditionally construct m_ptr depending on its type
    Holder(){ 
        if constexpr(is_unique_ptr<SmartPtr>::value){
            m_ptr = std::make_unique<value_type>();
        } else if constexpr(is_shared_ptr<SmartPtr>::value){
            m_ptr = std::make_shared<value_type>();
        } else {
            m_ptr = new value_type{};
        }
    }

private:

    SmartPtr m_ptr;

};

这个解决方案没有使用部分模板特化。然而如果你坚持使用部分模板特化,或者你没有c++17编译器,你将不得不对整个类进行不同指针类型的特化。

//generic class Holder (identical to your initial implementation)
template <class SmartPtr>
struct Holder {

    typedef typename SmartPtr::element_type value_type;

    Holder()
        : m_ptr(new value_type){
    }

private:

    SmartPtr m_ptr;

};

//this partial specialisation will be selected if template parameter is a std::unique_ptr 
template<typename T>
struct Holder<std::unique_ptr<T>>{
    using value_type = T;

    Holder() : m_ptr(std::make_unique<value_type>()){

    }

    private:
        std::unique_ptr<T> m_ptr;

};

//this partial specialisation will be selected if template parameter is a std::unique_ptr 
template<typename T>
struct Holder<std::shared_ptr<T>>{
    using value_type = T;

    Holder() : m_ptr(std::make_shared<value_type>()) {
    }

    private:
        std::shared_ptr<T> m_ptr;
};

使用部分模板特化,像这样,会导致代码膨胀。如果你决定使用这种解决方案,你可能需要考虑将常用方法分解到一个基类中,所有的特殊化都从这个基类中继承。这将有助于减少代码的臃肿。


0
投票

我想我想明白了这一点 (实况转播):

关键是要有一个模板化的构造函数,并带有 enable_if 确定它是否是一个有效的选择。

template <class SmartPtr>
struct Holder {

    typedef typename SmartPtr::element_type value_type;

    Holder()
        : m_ptr(new value_type)
    {}

    template <class T = value_type>
    Holder(std::enable_if_t<  std::is_same<shared_ptr<T>,SmartPtr>::value  >* = 0)
        : m_ptr(make_shared<T>())
    {}

private:

    SmartPtr m_ptr;

};

可能还有更好的方法---------------------------------。is_same 检查似乎有点黑客。但现在已经很好了。

© www.soinside.com 2019 - 2024. All rights reserved.