以编程方式在 C++ 中创建函数

Programmatically creating functions in c++

本文关键字:创建 函数 C++ 编程 方式      更新时间:2023-10-16

>假设我们有一个代码,其中包含 1000 个函数副本,形式如下:

function myname_[X](args){
struct somevariable_[X];
//others
}

其中 [X] 是一个序列,比如 0001、0002 等。

我打算通过以编程方式生成函数和变量名称来使其更干净。我们如何在 C++ 中做到这一点?

您可以使用模板生成编译时固定数量的 c 样式函数,每个函数都可以将硬编码参数传递给C++回调。可以使用该硬编码参数将 c 样式回调与对象相关联。

下面是一个最小的工作 C++14 示例,它允许将唯一的C++std::function与生成的每个 c 样式回调相关联。您可以使用 lambda 初始化该std::function,该 lambda 捕获您在该特定回调中所需的任何状态:

#include <iostream>
#include <algorithm>
#include <functional>
class Callbacks {
static constexpr unsigned count = 1000;
static Callbacks* instance;
using CF = void(); // C-style callback type.
using F = std::function<CF>; // C++ stateful callback type.
F callbacks_[count];
CF* c_style_callbacks_[count];
template<unsigned Index>
static void c_style_callback() {
instance->callbacks_[Index]();
}
template<unsigned... Index>
void make_c_style_callbacks(std::integer_sequence<unsigned, Index...>) {
auto initializer_list = {(c_style_callbacks_[Index] = &c_style_callback<Index>)...};
static_cast<void>(initializer_list);
}
public:
Callbacks() {
make_c_style_callbacks(std::make_integer_sequence<unsigned, count>{});
if(instance)
throw; // One instance only please.
instance = this;
}
Callbacks(Callbacks const&) = delete;
Callbacks& operator=(Callbacks const&) = delete;
~Callbacks() noexcept {
instance = 0;
}
CF* register_callback(F f) noexcept {
// Linear search can be improved upon.
auto condition = [](F const& f) { return !f; };
auto index = std::find_if(std::begin(callbacks_), std::end(callbacks_), condition) - std::begin(callbacks_);
if(index < count) {
callbacks_[index] = std::move(f); // Assumes move-assignement is noexcept.
return c_style_callbacks_[index];
}
return 0;
}
void unregister_callback(CF* cf) noexcept {
// Linear search can be improved upon.
auto index = std::find(std::begin(c_style_callbacks_), std::end(c_style_callbacks_), cf) - std::begin(c_style_callbacks_);
if(index < count)
callbacks_[index] = {};
else
throw; // cf has not been found. Programming error.
}
};
Callbacks* Callbacks::instance = 0;
int main() {
Callbacks c;
unsigned n = 0;
auto p0 = c.register_callback([m = n++]() { std::cout << m << 'n'; });
auto p1 = c.register_callback([m = n++]() { std::cout << m << 'n'; });
auto p2 = c.register_callback([m = n++]() { std::cout << m << 'n'; });
p0(); // Outputs 0.
p1(); // Outputs 1.
p2(); // Outputs 2.
c.unregister_callback(p2);
c.unregister_callback(p1);
c.unregister_callback(p0);
}

该解决方案需要使用一些全局状态,此处Callbacks::instance。另一种方法是通过引用具有链接的对象(内部或外部(来参数化c_style_callback,这意味着全局、命名空间范围或类静态对象。

如果您使用的是 C++11,则需要使用 C++14 中到达的std::integer_sequencestd::make_integer_sequence的向后移植,但实际上不需要任何特定于 C++14 的功能。自 C++14 起,命名捕获的示例[m = n++]也可用,但这只是演示。