【问题标题】:Queuing a call in headers在标头中排队呼叫
【发布时间】:2017-04-14 16:43:36
【问题描述】:

目标是允许头文件“注册”一个初始化函数,以便 main 可以遍历这些函数并调用它们。我偶然发现了一个使用 __attribute__ 的解决方案,但它似乎是 GCC-only (https://stackoverflow.com/a/37082249/7867841)。

// header1.h
void myInitializer(){}
REGISTER_THIS(&myInitializer);

// header2.h
void myInitializer2(){}
REGISTER_THIS(&myInitializer2);

// main.cpp
...
for_each_registered_ptr(){ call_ptr(); } // calls myInitializer and myInitializer2
...

有没有通用的解决方案?如果更容易实现,可以使用类或类型切换功能。

【问题讨论】:

    标签: c++ module extern


    【解决方案1】:

    您可以滥用static 函数本地人来执行此操作,避免静态初始化顺序失败。

    在init.h,我们有这个:

    #ifndef INIT_H
    #define INIT_H
    
    #include <vector>
    
    // Can be changed to std::function<...> or whatever you need.
    typedef void (*init_fn)();
    
    // Returns int so it can easily be used in a variable initializer.
    int register_initializer(init_fn fn);
    std::vector<init_fn> & get_initializers();
    
    #endif
    

    然后,在init.cpp:

    #include "init.h"
    
    int register_initializer(init_fn fn)
    {
        get_initializers().push_back(fn);
    
        return 0;
    }
    
    std::vector<init_fn> & get_initializers()
    {
        static std::vector<init_fn> ip;
    
        return ip;
    }
    

    一些注意事项,在我们继续其余部分之前:

    • static 本地只初始化一次,第一次调用该函数。
    • “全局”向量有点泄露。除非您向该向量添加数以万计的条目,否则这不太可能成为问题。用完后可以随时get_initializers().clear()清空。

    我们会这样使用它,在a.cpp:

    #include <iostream>
    
    #include "init.h"
    
    static void a_init() { std::cout << "a_init()\n"; }
    
    static auto dummy = register_initializer(a_init);
    

    最后,我们有我们的(相当简单的)main.cpp:

    #include "init.h"
    
    int main() {
        for (auto fn : get_initializers()) {
            fn();
        }
    
        return 0;
    }
    

    【讨论】:

    • 另外值得注意的是,这个解决方案只有从 C++11 开始是线程安全的(magic statics)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多