动态强制转换适用于模板成员函数内的共享指针和弱指针,无需代码重复

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

本文关键字:指针 代码 共享 适用于 转换 函数 成员 动态      更新时间:2023-10-16

我有我的 Find 方法,我想同时使用共享指针和弱指针。现场示例

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()方法的代码重复。

只需有一个模板函数,您可以使用它来获取"真实"指针。 std::shared_ptr的专用化只返回参数:

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函数代替iteratableList[i],使用resolve_pointer<T>::resolve(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();
}

如果您的目标是能够扩展代码以提供与具有已实现动态强制转换操作的任何强/弱指针对的互操作性(此处显示 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;
}

(演示(

然后,您的强制转换dynamic_pointer_cast<typename T::element_type>(iteratableList[i])变得dynamic_cast_helper<typename smart_pointer_info<T>::element_type>::cast(iteratableList[i]),编译器会推断出沿途的所有类型。