如何在编译期生成std::bind值的std::initializer_list?
编译期生成含
std::bind的std::initializer_list解决方案 问题描述
尝试通过模板函数在编译期创建包含std::bind值的std::initializer_list,但未能正确实现,原代码如下:
template<class T, int N> auto b(T t) -> auto { if constexpr (N == 0) { return std::initializer_list<????????>{ std::bind(t, 0) }; } else { return std::initializer_list { b<decltype(t), N-1>(t), std::bind(t, 0) }; } }
需求是避免编写重复的std::bind代码,比如:
char F(int c) { return 42; /* 实际会用c做相应操作 */ } // .... auto fs = { std::bind(F, 0), std::bind(F, 1), std::bind(F, 2), std::bind(F, 3), std::bind(F, 4), std::bind(F, 5) /* 等等...*/};
核心问题
原思路的根本问题在于:std::initializer_list无法通过递归拼接构造——它底层依赖临时数组,递归返回的initializer_list指向的临时对象会在函数返回后销毁,且语法上不支持将一个initializer_list与单个元素直接组合成新的initializer_list。
可行解决方案
方法一:利用编译期索引序列(推荐)
借助C++11引入的std::index_sequence生成编译期索引,一次性构造所有std::bind对象:
#include <functional> #include <utility> template<class Func, std::size_t... Is> auto make_bind_list_impl(Func func, std::index_sequence<Is...>) { using BindType = std::decay_t<decltype(std::bind(func, 0))>; return std::initializer_list<BindType>{ std::bind(func, Is)... }; } template<class Func, std::size_t N> auto make_bind_list(Func func) { return make_bind_list_impl(func, std::make_index_sequence<N>{}); }
使用示例:
char F(int c) { return 42 + c; } int main() { // 生成包含F绑定0到5的initializer_list(共6个元素) auto fs = make_bind_list<decltype(F), 6>(F); for (const auto& f : fs) { f(); // 调用每个绑定的函数 } }
该方法直接通过编译期序列展开构造对象,无生命周期问题,代码简洁高效。
方法二:模板递归生成索引序列
若不想依赖std::index_sequence,可通过模板递归生成索引,再展开构造:
#include <functional> template<class Func, int N, int... Is> struct BindListHelper { static auto create(Func func) { return BindListHelper<Func, N-1, N-1, Is...>::create(func); } }; template<class Func, int... Is> struct BindListHelper<Func, 0, Is...> { using BindType = std::decay_t<decltype(std::bind(func, 0))>; static auto create(Func func) { return std::initializer_list<BindType>{ std::bind(func, Is)... }; } }; template<class Func, int N> auto make_bind_list(Func func) { return BindListHelper<Func, N>::create(func); }
使用方式与方法一完全一致,本质是手动实现索引序列的生成逻辑。
关键注意事项
std::bind返回的是未指定类型,需用std::decay_t<decltype(std::bind(func, 0))>推导正确的类型作为initializer_list的模板参数。- 禁止递归拼接
initializer_list,否则会导致临时数组销毁后的悬空引用问题。
内容的提问来源于stack exchange,提问作者Ferenc Deak
相关产品推荐
相关产品推荐

