动态转换在模板成员函数内部同时使用共享指针和弱指针,无需代码重复

Dynamic casting work both shared and weak pointers inside of template member function without code duplication

我有我的 Find 方法,我想将其与共享指针和弱指针一起使用。 Live example

using namespace std;

    template<typename value> 
    struct A 
    {
        template < typename T, typename F >
        T Find( F filterFunction)
        {
            for ( size_t i = 0; i < iteratableList.size(); i++)
            {
                auto castedTerrain = dynamic_pointer_cast<typename T::element_type>(iteratableList[i]);
                if ( castedTerrain && filterFunction(castedTerrain) )
                    return iteratableList[i];
            }
            return T();
        }

        std::vector<value> iteratableList;
    };

int main()
{
    {
        std::vector<std::shared_ptr<std::string>> names = {  make_shared<std::string>("needle"), make_shared<std::string>("manyOtherNames") } ; 
        A<std::shared_ptr<std::string>> iterateable{ names }; 
        iterateable.Find<std::shared_ptr<std::string>>([] ( std::shared_ptr<std::string> in ){ return  *in == "needle";});
    }

    // When I use weak pointer my Find function fails.
    //{
    //    std::vector<std::shared_ptr<std::string>> weakNames  ;
    //    for ( auto elem : names )
    //          weakNames.push_back(elem)
    //    A<std::weak_ptr<std::string>> iterateable{ weakNames }; 
    //    iterateable.Find<std::weak_ptr<std::string>>([] ( std::weak_ptr<std::string> in ){ return  *in == "needle";});
    //}
}

我知道我可以做类似的事情 std::is_same< std::weak_ptr ... > 并使用 std::true_typestd::false_type 但我很好奇是否有更好更清晰的方法来避免仅针对 .lock() 方法的代码重复。

只要有一个模板函数就可以用来获取"real"指针。 std::shared_ptr 的特化只是 returns 参数:

template <typename T>
struct resolve_pointer;

template <typename T>
struct resolve_pointer<std::shared_ptr<T>>
{
    static std::shared_ptr<T> resolve(std::shared_ptr<T> & p) const {
        return p;
    }
};

template <typename T>
struct resolve_pointer<std::weak_ptr<T>>
{
    static std::shared_ptr<T> resolve(std::weak_ptr<T> & p) const {
        return p.lock();
    }
};

现在你的 Find 函数,用 resolve_pointer<T>::resolve(iteratableList[i]).

代替 iteratableList[i]

我是个土豆,一个重载的自由函数也可以工作,而且更容易理解:

template <typename T>
std::shared_ptr<T> resolve_pointer(std::shared_ptr<T> & p) {
    return p;
}

template <typename T>
std::shared_ptr<T> resolve_pointer(std::weak_ptr<T> & p) {
    return p.lock();
}

如果您的目标是能够扩展您的代码以提供与任何 strong/weak 指针对的互操作性,这些指针对具有已实现的动态转换操作(此处显示 std::strong/weak_ptr 和 boost ::strong/weak_ptr),你可以使用一组特征来做到这一点,就像这样......当心,前方有龙:

// Defines a resolve static function to get a strong pointer from either
// a strong or a weak pointer.
template <typename T>
struct smart_pointer_info;

template <typename T>
struct smart_pointer_info<std::shared_ptr<T>>
{
    typedef std::shared_ptr<T> ptr_type;
    typedef T element_type;
    typedef std::shared_ptr<T> resolved_type;

    static resolved_type resolve(ptr_type & p) {
        return p;
    }
};

template <typename T>
struct smart_pointer_info<std::weak_ptr<T>>
{
    typedef std::weak_ptr<T> ptr_type;
    typedef T element_type;
    typedef std::shared_ptr<T> resolved_type;

    static resolved_type resolve(ptr_type & p) {
        return p.lock();
    }
};

template <typename T>
struct smart_pointer_info<boost::shared_ptr<T>>
{
    typedef boost::shared_ptr<T> ptr_type;
    typedef T element_type;
    typedef boost::shared_ptr<T> resolved_type;

    static resolved_type resolve(ptr_type & p) {
        return p;
    }
};

template <typename T>
struct smart_pointer_info<boost::weak_ptr<T>>
{
    typedef boost::weak_ptr<T> ptr_type;
    typedef T element_type;
    typedef boost::shared_ptr<T> resolved_type;

    static resolved_type resolve(ptr_type & p) {
        return p.lock();
    }
};

// Provides a static "cast" function that converts a strong pointer T
// into a strong point that points at an object of type D.
template <typename T, typename D>
struct smart_pointer_dynamic_cast;

template <typename T, typename D>
struct smart_pointer_dynamic_cast<std::shared_ptr<T>, D>
{
    typedef std::shared_ptr<T> ptr_type;
    typedef std::shared_ptr<D> cast_type;

    static cast_type cast(ptr_type & p) {
        return std::dynamic_pointer_cast<D>(p);
    }
};

template <typename T, typename D>
struct smart_pointer_dynamic_cast<boost::shared_ptr<T>, D>
{
    typedef boost::shared_ptr<T> ptr_type;
    typedef boost::shared_ptr<D> cast_type;

    static cast_type cast(ptr_type & p) {
        return boost::dynamic_pointer_cast<D>(p);
    }
};

// Helper so we can omit the template parameter for the source pointer type.
template <typename D>
struct dynamic_cast_helper
{
    template <typename P>
    static typename smart_pointer_dynamic_cast<typename smart_pointer_info<P>::resolved_type, D>::cast_type cast(P & p) {
        typename smart_pointer_info<P>::resolved_type r = smart_pointer_info<P>::resolve(p);

        return smart_pointer_dynamic_cast<typename smart_pointer_info<P>::resolved_type, D>::cast(r);
    }
};

// Then we might use it like so:
class A {
public:
    virtual void print() {
        std::cout << "A::print()" << std::endl;
    }
};

class B : public A {
public:
    virtual void print() {
        std::cout << "B::print()" << std::endl;
    }
};

int main()
{
    auto x = std::make_shared<B>();
    std::weak_ptr<B> xw{x};

    auto y = boost::make_shared<B>();
    boost::weak_ptr<B> yw{y};

    dynamic_cast_helper<A>::cast(x)->print();
    dynamic_cast_helper<A>::cast(xw)->print();
    dynamic_cast_helper<A>::cast(y)->print();
    dynamic_cast_helper<A>::cast(yw)->print();

    return 0;
}

(Demo)

你的转换 dynamic_pointer_cast<typename T::element_type>(iteratableList[i]) 然后变成 dynamic_cast_helper<typename smart_pointer_info<T>::element_type>::cast(iteratableList[i]) 并且沿途的所有类型都被编译器推断出来。