生成指向回调函数的常量指针数组
Generate const array of pointers to callback functions
我想生成一个包含 N 个回调指针的数组,这样我就不必显式键入它们(这里的 LOC 不是问题)。
我使用 C++17.
这是我的:
using Callback = void(*)();
auto constexpr N = 2;
const Callback callbacks[N] = {
[](){ auto i = 0; std::cout<<"callback " << i << "\n";},
[](){ auto i = 1; std::cout<<"callback " << i << "\n";}
};
callbacks[0]();
callbacks[N-1]();
这是我想要的:
const auto callbacks = generate_callbacks<N>(); // or generate_callbacks(N)
callbacks[i](); // cout<<"callback " << i << "\n";
我尝试了各种方法,但我一直 运行 研究常量参数的问题,即使它们来自 constexpr 函数或可变参数模板。
如果我试试这个:
Callback callbacks[N] = { };
for(int i=0;i<N;++i)
{
callbacks[i] = [i](){ std::cout<<"callback " << i << "\n";};
}
for(int i=0;i<N;++i)
{
callbacks[i]();
}
我收到以下错误:
main.cpp:91:66: error: cannot convert ‘main()::’ to ‘Callback {aka void (*)()}’ in assignment
callbacks[i] = [i](){ std::cout<<"callback " << i << "\n";};
如果我将 i 设为静态并省略捕获,它只使用 i 的最后一个值:
callback 2
callback 2
这对我来说很奇怪,因为捕获应该在构造时完成。 lambda 是在循环退出后构造的吗?
至于目的。我想应用这种技术为微控制器生成中断处理程序。我可以直接把函数指针放在中断向量table中。这些函数没有参数,而且我也不知道检测调用处理程序的中断源的简洁方法。我可以为每个中断编写一个处理程序,但我不喜欢将这段代码重复 6 次:
void handler0()
{
do_something(0);
}
使用模板将其键入为 lambda and/or 使其更清晰一些,但我仍然需要键入 N 次内容。如果 N 发生变化,我必须更改多行代码。这不优雅。
题外话建议:尽可能不要使用 C-styles 数组,而是使用 C++ std::array
.
例如:下面一行
const auto callbacks = generate_callbacks<N>();
如果您希望 callbacks
是一个 C-style 数组(函数不能 return 该类型)则无法工作,但在 generate_callback()
return一个std::array<Callback, N>
实例。
题外话建议结束。
在这种特殊情况下,鉴于 N
是一个 constexpr
值,我建议使用模板 meta-programming.
所以我建议使用以下 generate_callbacks()
函数,它只创建一个从零到 N-1
的模板值序列并调用辅助函数
template <std::size_t N>
auto generate_callbacks ()
{ return gc_helper(std::make_index_sequence<N>{}); }
和一个简单的辅助函数,它使用模板值并创建回调 lambda 而不捕获它们(因此仍然可以转换为函数指针)
template <std::size_t ... Is>
std::array<Callback, sizeof...(Is)> gc_helper (std::index_sequence<Is...>)
{ return {{ []{ auto i = Is; std::cout<<"callback " << i << "\n"; }... }}; }
如果您可以使用 C++20,使用模板 lambda,您可以避免使用外部 gc_helper()
函数,并在 generate_callbacks()
内部进行如下操作
template <std::size_t N>
auto generate_callbacks ()
{
return []<std::size_t ... Is>(std::index_sequence<Is...>)
-> std::array<Callback, N>
{ return {{ []{ std::cout<<"callback " << Is << "\n"; }... }}; }
(std::make_index_sequence<N>{});
}
以下为完整编译C++17 C++14范例
#include <iostream>
#include <utility>
#include <array>
using Callback = void(*)();
auto constexpr N = 2;
template <std::size_t ... Is>
std::array<Callback, sizeof...(Is)> gc_helper (std::index_sequence<Is...>)
{ return {{ []{ auto i = Is; std::cout<<"callback " << i << "\n"; }... }}; }
template <std::size_t N>
auto generate_callbacks ()
{ return gc_helper(std::make_index_sequence<N>{}); }
int main()
{
const auto callbacks = generate_callbacks<N>();
for ( auto ui = 0 ; ui < N ; ++ui )
callbacks[ui]();
}
以下代码在 C++17 模式下的 gcc 和 clang 中都可以正常编译。它使用一些简单的模板元编程来生成回调序列。
#include <array>
#include <iostream>
using cb = void (*)();
template<int N>
inline auto fun()
{
std::cout << "callback: " << N << '\n';
}
template<int N>
void init(cb * arr)
{
arr[N] = &fun<N>;
init<N-1>(arr);
}
template<>
void init<0>(cb * arr)
{
arr[0] = &fun<0>;
}
template<int N>
struct callbacks
{
callbacks()
{
init<N>(cbs.data());
}
std::array<cb, N> cbs;
};
int main()
{
auto foo = callbacks<4>();
for (auto x = 0; x < 4; ++x)
{
foo.cbs[x]();
}
}
我想生成一个包含 N 个回调指针的数组,这样我就不必显式键入它们(这里的 LOC 不是问题)。 我使用 C++17.
这是我的:
using Callback = void(*)();
auto constexpr N = 2;
const Callback callbacks[N] = {
[](){ auto i = 0; std::cout<<"callback " << i << "\n";},
[](){ auto i = 1; std::cout<<"callback " << i << "\n";}
};
callbacks[0]();
callbacks[N-1]();
这是我想要的:
const auto callbacks = generate_callbacks<N>(); // or generate_callbacks(N)
callbacks[i](); // cout<<"callback " << i << "\n";
我尝试了各种方法,但我一直 运行 研究常量参数的问题,即使它们来自 constexpr 函数或可变参数模板。
如果我试试这个:
Callback callbacks[N] = { };
for(int i=0;i<N;++i)
{
callbacks[i] = [i](){ std::cout<<"callback " << i << "\n";};
}
for(int i=0;i<N;++i)
{
callbacks[i]();
}
我收到以下错误:
main.cpp:91:66: error: cannot convert ‘main()::’ to ‘Callback {aka void (*)()}’ in assignment
callbacks[i] = [i](){ std::cout<<"callback " << i << "\n";};
如果我将 i 设为静态并省略捕获,它只使用 i 的最后一个值:
callback 2
callback 2
这对我来说很奇怪,因为捕获应该在构造时完成。 lambda 是在循环退出后构造的吗?
至于目的。我想应用这种技术为微控制器生成中断处理程序。我可以直接把函数指针放在中断向量table中。这些函数没有参数,而且我也不知道检测调用处理程序的中断源的简洁方法。我可以为每个中断编写一个处理程序,但我不喜欢将这段代码重复 6 次:
void handler0()
{
do_something(0);
}
使用模板将其键入为 lambda and/or 使其更清晰一些,但我仍然需要键入 N 次内容。如果 N 发生变化,我必须更改多行代码。这不优雅。
题外话建议:尽可能不要使用 C-styles 数组,而是使用 C++ std::array
.
例如:下面一行
const auto callbacks = generate_callbacks<N>();
如果您希望 callbacks
是一个 C-style 数组(函数不能 return 该类型)则无法工作,但在 generate_callback()
return一个std::array<Callback, N>
实例。
题外话建议结束。
在这种特殊情况下,鉴于 N
是一个 constexpr
值,我建议使用模板 meta-programming.
所以我建议使用以下 generate_callbacks()
函数,它只创建一个从零到 N-1
的模板值序列并调用辅助函数
template <std::size_t N>
auto generate_callbacks ()
{ return gc_helper(std::make_index_sequence<N>{}); }
和一个简单的辅助函数,它使用模板值并创建回调 lambda 而不捕获它们(因此仍然可以转换为函数指针)
template <std::size_t ... Is>
std::array<Callback, sizeof...(Is)> gc_helper (std::index_sequence<Is...>)
{ return {{ []{ auto i = Is; std::cout<<"callback " << i << "\n"; }... }}; }
如果您可以使用 C++20,使用模板 lambda,您可以避免使用外部 gc_helper()
函数,并在 generate_callbacks()
内部进行如下操作
template <std::size_t N>
auto generate_callbacks ()
{
return []<std::size_t ... Is>(std::index_sequence<Is...>)
-> std::array<Callback, N>
{ return {{ []{ std::cout<<"callback " << Is << "\n"; }... }}; }
(std::make_index_sequence<N>{});
}
以下为完整编译C++17 C++14范例
#include <iostream>
#include <utility>
#include <array>
using Callback = void(*)();
auto constexpr N = 2;
template <std::size_t ... Is>
std::array<Callback, sizeof...(Is)> gc_helper (std::index_sequence<Is...>)
{ return {{ []{ auto i = Is; std::cout<<"callback " << i << "\n"; }... }}; }
template <std::size_t N>
auto generate_callbacks ()
{ return gc_helper(std::make_index_sequence<N>{}); }
int main()
{
const auto callbacks = generate_callbacks<N>();
for ( auto ui = 0 ; ui < N ; ++ui )
callbacks[ui]();
}
以下代码在 C++17 模式下的 gcc 和 clang 中都可以正常编译。它使用一些简单的模板元编程来生成回调序列。
#include <array>
#include <iostream>
using cb = void (*)();
template<int N>
inline auto fun()
{
std::cout << "callback: " << N << '\n';
}
template<int N>
void init(cb * arr)
{
arr[N] = &fun<N>;
init<N-1>(arr);
}
template<>
void init<0>(cb * arr)
{
arr[0] = &fun<0>;
}
template<int N>
struct callbacks
{
callbacks()
{
init<N>(cbs.data());
}
std::array<cb, N> cbs;
};
int main()
{
auto foo = callbacks<4>();
for (auto x = 0; x < 4; ++x)
{
foo.cbs[x]();
}
}