首页 > 解决方案 > 有没有一种方法可以调用为反射创建的每个模板实例的函数?

问题描述

我找到了一种我认为可以很好地跟踪我的程序中实例化了哪些模板的方法,我发现这对我非常有用:

constinit const char* loggerTypesCreated[32];
int count = 0;

template <typename T>
struct MyLogger
{
    static inline char usedVariable = rand();
    static inline char dummy = []()
    {
        loggerTypesCreated[count] = typeid(T).name();
        ++count;

        return char(); // dummy
    }();
};
    
int main()
{
    MyLogger<int>{}, MyLogger<char>{}, MyLogger<double>{}, MyLogger<float>{};

    std::cout << "Loggers created:\n";
    for (int i = 0; i < count; ++i)
        std::cout << "Logger<" << loggerTypesCreated[i] << ">\n";
}

虽然dummy类中的数组和静态都是静态的,但初始化顺序是定义的,因为数组是“常量”初始化的。据我所知,您也可以这样做,std::vector因为默认构造函数是constexpr, 并且不断初始化。

无论如何,对我来说,以上述方式在程序开始时运行一个函数对我注册我创建的类型非常有用,但是有没有办法在没有dummy变量的情况下做到这一点?

此外,dummy变量是否有被优化的风险,因为它没有被使用?它的初始化程序有副作用,但我不知道它是否重要。

这对我来说非常有用,包括在函数中放置计时器。

编辑:如果不清楚,我不希望在创建对象时调用初始化函数,我希望它是这样的:

void functionToBeTimed
{
     Timer</a_unique_type/> timer;
     // Not when the object is created, but at program startup
// to initialise all instantiated templates.
}

标签: c++templatesloggingstaticc++20

解决方案


有没有办法在没有虚拟变量的情况下做到这一点?

您可以为静态立即调用的 lambda提供(可选constexpr)构造函数并移动您在其中的定义。MyLoggerdummy

template <typename T> struct MyLogger
{
    constexpr MyLogger() noexcept
    {    
        loggerTypesCreated[count] = typeid(T).name();
        ++count;
    }
    static inline char usedVariable = rand(); // --> do you need this??
};

这样,您就可以loggerTypesCreatedMyLogger创建对象时进行更新,而不必担心冗余dummy变量以及优化问题。

此外,您可以将 移动MyLogger<int>{}, MyLogger<char>{}, MyLogger<double>{}, MyLogger<float>{}到模板化函数。

template<typename... Args>
constexpr void log_types() noexcept
{
    (MyLogger<Args>{}, ...);
}

对象创建就像:

log_types<int, char, double, float>();

看一个演示在这里


推荐阅读