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

嵌入式无RTTI场景下高效dynamic_cast实现的二进制优化问题

我正在开发一款面向嵌入式系统的库,因此无法使用包括dynamic_cast在内的任何RTTI特性。为了实现类似dynamic_cast的功能,我参考相关技术文章自行实现了RTTI的必要组件,部分实现细节有调整但核心思路一致。

初始实现代码
#include <iostream>

constexpr uint32_t primes[] = {
        2,
        3,
        5,
        7,
        11,
        13,
        17,
        19,
        23,
        29,
        31
};

#define DYNAMIC_POINTER_CAST_INIT(...)                                                           \
    virtual uint32_t dynamicPointerCastObjectId() override                                       \
    {                                                                                            \
        return DynamicPointerCastable<__VA_ARGS__>::dynamicPointerCastObjectId(); \
    }                                                                                            \
                                                                                                 \
    using DynamicPointerCastable<__VA_ARGS__>::dynamicPointerCastClassId;         \
    using DynamicPointerCastable<__VA_ARGS__>::dynamicPointerCastClassPrimeId

namespace
{
    uint32_t numberOfDynamicPointerCastables = 0;

    template <typename... Bs>
    struct genSubClassId
    {
        static uint32_t value;
    };

    template <typename B, typename... Bs>
    struct genSubClassId<B, Bs...>
    {
        static uint32_t value;
    };

    template <typename B>
    struct genSubClassId<B>
    {
        static uint32_t value;
    };
    template <>
    struct genSubClassId<>
    {
        static uint32_t value;
    };

    template <typename B, typename... Bs>
    uint32_t genSubClassId<B, Bs...>::value =
            B::dynamicPointerCastClassId() * genSubClassId<Bs...>::value;
    template <typename B>
    uint32_t genSubClassId<B>::value =
            B::dynamicPointerCastClassId();

    uint32_t genSubClassId<>::value = 1;
}

template <typename Sub, typename... Bases>
class DynamicPointerCastable
{

private:
    static uint32_t subPrimeId;

public:
    static uint32_t dynamicPointerCastClassPrimeId()
    {
        return subPrimeId;
    }

    static uint32_t dynamicPointerCastClassId()
    {
        return subPrimeId * genSubClassId<Bases...>::value;
    }

    virtual uint32_t dynamicPointerCastObjectId()
    {
        return DynamicPointerCastable<Sub, Bases...>::dynamicPointerCastClassId();
    }
};

template <typename T, typename Cast>
Cast *dynamicCastableCast(T *obj)
{
    if (obj->dynamicPointerCastObjectId() % Cast::dynamicPointerCastClassPrimeId() == 0)
        return (Cast *)obj;
    return nullptr;
}

template <typename Sub, typename... Bases>
uint32_t DynamicPointerCastable<Sub, Bases...>::subPrimeId = primes[numberOfDynamicPointerCastables++];
核心实现思路

我设置了计数器numberOfDynamicPointerCastables作为素数数组primes(库内该数组共包含1000个素数)的索引,通过CRTP(奇异递归模板模式)在子类中实现DynamicPointerCastable的相关方法,dynamicCastableCast函数通过检查对象ID是否能被目标转换类型关联的素数整除,完成类型转换合法性校验。

使用示例
struct Sub1 : public Base, public DynamicPointerCastable<Sub1, Base>
{
    DYNAMIC_POINTER_CAST_INIT(Sub1, Base);
    virtual std::string getName()
    {
        return "Sub1";
    }
};

struct SubGroup : public Base, public DynamicPointerCastable<SubGroup, Base>
{
    DYNAMIC_POINTER_CAST_INIT(SubGroup, Base);
    virtual std::string getName()
    {
        return "SubGroup";
    }
};

struct Sub2 : public SubGroup, public DynamicPointerCastable<Sub2, SubGroup>
{
    DYNAMIC_POINTER_CAST_INIT(Sub2, SubGroup);
    virtual std::string getName()
    {
        return "Sub2";
    }
};

int main()
{
    Base* sub1 = new Sub1;
    Base* sub2 = new Sub2;

    std::cout << "Expected Sub1: " << dynamicCastableCast<Base, Sub1>(sub1)->getName() << std::endl;
    std::cout << "Expected nullptr: " << dynamicCastableCast<Base, Sub2>(sub1) << std::endl;

    std::cout << "Expected Sub2: " << dynamicCastableCast<Base, SubGroup>(sub2)->getName() << std::endl;
    std::cout << "Expected Sub2: " << dynamicCastableCast<Base, Sub2>(sub2)->getName() << std::endl;
    std::cout << "Expected nullptr: " << dynamicCastableCast<Base, Sub1>(sub2) << std::endl;
}
待解决问题

目前我未能实现编译期计数,导致整个素数数组都会被编入二进制(我使用gcc-11,编译参数为-Os -ffunction-sections -fdata-sections -Wl,--gc-sections -DNDEBUG)。我想咨询以下问题:

  • 如果实现了编译期类计数,编译器能否只将用到的素数编入二进制?
  • 如果可以的话,如何实现编译期计数器?
  • 是否有其他方案可以尽可能缩小二进制体积?
后续更新

我已经实现了一个元函数,在默认-ftemplate-depth=900的参数下最多可以生成第131个素数,131个素数基本可以满足需求,后续我会优化该实现降低模板深度。我也将测试其他方案的程序体积,目前的问题是prime<...>::atIndex()方法的编译耗时过长。

新实现代码

#include <iostream>

template<size_t n, size_t i = 2>
constexpr typename std::enable_if<!(i * i <= n), bool>::type isPrime() noexcept
{
    return true;
}

template<size_t n, size_t i = 2>
constexpr typename std::enable_if<i * i <= n, bool>::type isPrime() noexcept
{
    return (n % i != 0) && isPrime<n, i + 1>();
}


template<size_t i, size_t counter = 0, size_t k = 3, typename Enabled = void>
struct prime;

template<size_t i, size_t counter, size_t k>
struct prime<i, counter, k, typename std::enable_if<isPrime<k>() && counter < i>::type>
{
    static constexpr size_t atIndex() noexcept
    {
        return prime<i, counter + 1, k + 1>::atIndex();
    }
};

template<size_t i, size_t counter, size_t k>
struct prime<i, counter, k, typename std::enable_if<!isPrime<k>() && counter < i>::type>
{
    static constexpr size_t atIndex() noexcept
    {
        return prime<i, counter, k + 1>::atIndex();
    }
};

template<size_t i, size_t counter, size_t k>
struct prime<i, counter, k, typename std::enable_if<isPrime<k>() && counter >= i>::type>
{
    static constexpr size_t atIndex() noexcept
    {
        return k - 1;
    }
};

template<size_t i, size_t counter, size_t k>
struct prime<i, counter, k, typename std::enable_if<!isPrime<k>() && counter >= i>::type>
{
    static constexpr size_t atIndex() noexcept
    {
        return k - 1;
    }
};

template<int until, int step, template<int> typename op, int i = 0>
struct constFor
{
    constFor()
    {
        op<i>{};
        constFor<until, step, op, i + step>{};
    }
};

template<int until, int step, template<int> typename op>
struct constFor<until, step, op, until>
{
    constFor() = default;
};

template<int i>
struct print
{
    print()
    {
        std::cout << prime<i>::atIndex() << std::endl;
    }
};

int main()
{
    constFor<131, 1, print>{};
}

内容的提问来源于stack exchange,提问作者Gian Laager

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 15:57:00