生成代码(在编译时)以调用模板的每个实例化的静态函数

Generating code (at compile-time) to call a static function of every instantiation of a template

我的问题可以用下面的例子来描述。

我想从模板的每个实例化中调用一个静态函数。我在想的是类似于元组的东西,每次遇到模板的新实例时它都会扩展,这样我就可以递归地访问该元组并调用元组中每种类型的静态函数。

#include <vector>

template<typename T>
    struct Junk
    {
        static std::vector<T> all;
        Junk(T t)
        {
            all.push_back(t);
        }

        static void clear()
        {
            all.clear();
        }
    };

template<typename T>
    std::vector<T> Junk<T>::all;

void clearJunk()
{
    Junk<float>::clear();
    Junk<char>::clear();
    Junk<unsigned int>::clear();        
    // how can I generalize this?
}

int main()
{
    // instantiate Junk with different types
    Junk<float> f1(1.0f);
    Junk<float> f2(2.0f);
    // Junk<float>::all.size() == 2

    Junk<char> c1('a');
    Junk<char> c2('b');
    Junk<char> c3('c');
    // Junk<char>::all.size() == 3

    Junk<unsigned int> i1(1);
    // Junk<unsigned int>::all.size() == 1

    // clear all Junk
    clearJunk();

    return 0;
}

一个 运行 时间的解决方案是函数指针向量,每个模板实例化的第一个对象将指向静态成员函数的指针推送到该向量:

std::vector<void(*)()> clear_funcs;

template<typename T>
    struct Junk
    {
        static std::vector<T> all;
        Junk(T t)
        {
            (void)init;   // mention init at least once so its constructor will be invoked
            all.push_back(t);
        }

        static void clear()
        {
            all.clear();
        }
        struct At_Init
        {
            At_Init()
            {
                clear_funcs.push_back(&Junk<T>::clear);
            }
        };
        static At_Init init; // will only be constructed once for each template instantiation
    };

template<typename T>
    std::vector<T> Junk<T>::all;

template<typename T>
    typename Junk<T>::At_Init Junk<T>::init;

void clearJunk()
{
    // call every clear() of all the Junk template instantiations
    for (void(*clear)() : clear_funcs) {
        clear();
    }
}

但是这个解决方案不如编译时解决方案快,并且它需要 class 中的大量代码,这些代码根本没有意义,所以我不喜欢这个解决方案,尽管它可以工作。

如何在编译时生成代码来调用模板的每个实例化的静态函数?

你运气不好。

要了解原因,假设有 3 个动态库。他们每个人都使用 Junk<typeX>,其中 X 是 0、1 或 2。

这些库在程序运行后加载,具体取决于月相。

没有中央位置可能知道在编译时调用哪些 Junk<?>::clear() 方法。为了知道要调用哪些方法,您必须有一个中央位置负责它并在运行时跟踪实例化了哪些 Junk<?> 类型。

现在,您可能没有使用动态库,但语言(实际上)支持动态库这一事实意味着没有办法跟踪交叉编译单元以及从模板实例化的所有类型的枚举,而无需将其存储为运行时状态。编译时,每个编译单元(cpp文件)可以单独编译。

当然有办法解决这个问题;如果您只有一个编译单元(甚至是一个统一构建),或者如果您维护了一个支持类型的中央列表(如果您错过了类型,则可以选择生成硬编译时错误),您可以生成类似于静态代码案例的代码。

但在你这样做之前,分析你的简单动态解决方案并确保它是一个实际问题。