如何绕过GCC bug,创建可立即访问的自动类型函数指针向量?
针对GCC<12函数指针vector初始化访问问题的解决方案
GCC 12以下版本存在编号87709的已知bug,无法直接初始化隐式类型std::vector并链式访问元素(如(std::vector {1,2,3})[0]编译失败)。针对普通类型的decltype workaround对函数指针完全无效:直接用隐式类型初始化函数指针vector会在GCC编译失败,而std::vector<decltype(f)>会在Clang和GCC中触发allocator的address函数重载冲突。
以下是无需显式声明函数指针签名的可行方案,适配带模板参数的函数指针场景:
方案1:模板推导函数(推荐,无宏)
通过模板函数自动推导函数指针类型,先构造vector再访问元素,避开GCC的临时对象链式访问bug:
#include <vector> template<typename FuncPtr> auto get_vec_element(FuncPtr first, size_t idx, auto... rest) { std::vector<FuncPtr> vec{first, rest...}; return vec[idx]; } // 测试用例 void foo() {} void bar(int) {} template<typename T> void baz(T) {} int main() { // 无模板参数的函数指针 auto elem1 = get_vec_element(foo, 0); elem1(); // 带参数的函数指针 auto elem2 = get_vec_element(bar, 0, [](int){}); elem2(42); // 带模板参数的函数指针 auto elem3 = get_vec_element(&baz<int>, 1, &baz<double>); elem3(3.14); return 0; }
模板会自动推导传入的函数指针类型,无需手动写std::vector<void(*)()>或std::vector<void(*)(int)>这类签名,同时兼容GCC<12和Clang。
方案2:适配宏需求的封装
如果需要保留类似宏的简洁调用方式,可将模板函数包装成宏:
#include <vector> template<typename FuncPtr> auto _vec_elem_impl(FuncPtr first, size_t idx, auto... rest) { std::vector<FuncPtr> vec{first, rest...}; return vec[idx]; } // 宏定义:第一个参数是索引,后续是函数指针列表 #define GET_VEC_ELEM(idx, ...) _vec_elem_impl(__VA_ARGS__, idx) // 测试 void foo() {} void bar() {} int main() { auto elem = GET_VEC_ELEM(1, foo, bar); // 获取第1个元素bar elem(); return 0; }
宏仅做参数转发,核心逻辑还是模板推导,既保持调用简洁,又避免重复编写函数签名。
方案3:类模板推导+拆分步骤(极简)
如果不需要链式表达式,直接拆分vector构造和元素访问即可,借助C++17的类模板推导自动识别类型:
#include <vector> void foo() {} void bar() {} int main() { auto vec = std::vector{foo, bar}; auto elem = vec[0]; elem(); // 如果要在表达式内使用,用lambda包装 auto elem_in_expr = []{ auto vec = std::vector{foo, bar}; return vec[1]; }(); elem_in_expr(); return 0; }
这个方案代码最简洁,完全依赖语言本身的推导特性,无需额外模板或宏。
内容的提问来源于stack exchange,提问作者Anti Earth
相关产品推荐
相关产品推荐

