You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否实现可获取基类指针的安全非UB版std::any?

问题

免责声明:本问题纯属假设,本人实际会直接使用抽象接口。

据我了解,std::any_cast<T>有一个重载版本,接受std::any指针,若其包含T则返回T指针,否则返回nullptr。

该行为与dynamic_cast类似,但局限性更大,因为dynamic_cast允许在继承链的任意类之间向上或向下转换。

但std::any_cast无法做到这点:必须先显式转换为包含的对象,再通过static_cast转换为基类,这限制了std::any的多态使用价值。

那么,是否能实现一个支持获取基类指针的安全非UB版any?


实现方案

可以实现一个支持多态转换的polymorphic_any,核心是在类型擦除时保留动态转换的能力,以下是一个安全无UB的实现:

#include <any>
#include <typeinfo>
#include <memory>
#include <stdexcept>
#include <type_traits>

class polymorphic_any {
private:
    struct placeholder_base {
        virtual ~placeholder_base() = default;
        virtual void* try_cast(const std::type_info& target) const = 0;
        virtual const std::type_info& type() const = 0;
        virtual placeholder_base* clone() const = 0;
    };

    template<typename T>
    struct placeholder : placeholder_base {
        T value;

        explicit placeholder(T val) : value(std::move(val)) {}

        void* try_cast(const std::type_info& target) const override {
            // 优先匹配原始类型
            if (typeid(T) == target) {
                return const_cast<void*>(static_cast<const void*>(&value));
            }
            // 对多态类型尝试动态转换
            if constexpr (std::is_polymorphic_v<T>) {
                return dynamic_cast<void*>(const_cast<T*>(&value));
            }
            return nullptr;
        }

        const std::type_info& type() const override {
            return typeid(T);
        }

        placeholder_base* clone() const override {
            return new placeholder<T>(value);
        }
    };

    std::unique_ptr<placeholder_base> content;

public:
    polymorphic_any() = default;

    template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, polymorphic_any>>>
    polymorphic_any(T&& val) : content(std::make_unique<placeholder<std::decay_t<T>>>(std::forward<T>(val))) {}

    polymorphic_any(const polymorphic_any& other) {
        if (other.content) {
            content.reset(other.content->clone());
        }
    }

    polymorphic_any(polymorphic_any&& other) noexcept = default;
    polymorphic_any& operator=(polymorphic_any&& other) noexcept = default;
    polymorphic_any& operator=(const polymorphic_any& other) {
        if (this != &other) {
            if (other.content) {
                content.reset(other.content->clone());
            } else {
                content.reset();
            }
        }
        return *this;
    }

    bool has_value() const noexcept {
        return content != nullptr;
    }

    const std::type_info& type() const noexcept {
        return content ? content->type() : typeid(void);
    }

    void reset() noexcept {
        content.reset();
    }
};

template<typename T>
T* any_cast(polymorphic_any* any_ptr) {
    if (!any_ptr || !any_ptr->has_value()) {
        return nullptr;
    }
    void* ptr = any_ptr->content->try_cast(typeid(T));
    return static_cast<T*>(ptr);
}

template<typename T>
const T* any_cast(const polymorphic_any* any_ptr) {
    return any_cast<T>(const_cast<polymorphic_any*>(any_ptr));
}

template<typename T>
T any_cast(polymorphic_any& any_val) {
    T* ptr = any_cast<T>(&any_val);
    if (!ptr) {
        throw std::bad_any_cast();
    }
    return *ptr;
}

template<typename T>
T any_cast(const polymorphic_any& any_val) {
    return any_cast<const T>(const_cast<polymorphic_any&>(any_val));
}

关键说明

  • 这个实现通过placeholder<T>的try_cast方法,结合dynamic_cast实现了多态转换:当存储的类型T是多态类型(包含虚函数)时,能安全转换到其继承链中的基类或派生类指针,行为和dynamic_cast完全一致,保证无UB。
  • 对于非多态类型,仅支持转换到原始类型,和标准std::any行为一致,避免不安全的跨类型转换。
  • 完整实现了值语义(拷贝、赋值),通过clone方法完成存储对象的深拷贝,符合常规容器的使用习惯。

内容的提问来源于stack exchange,提问作者Sergey Kolesnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:12:42