C++如何正确将lambda函数存入tuple并调用?错误排查与实现方案
问题原因
- 函数签名不匹配:类内定义的
Func<Type>别名是返回bool、入参为Type const&的函数类型,但main中传入的lambda参数声明为int&/std::string&,缺少const修饰符,无捕获lambda虽然支持隐式转换为函数指针,但要求签名完全匹配才可以转换,因此构造时找不到匹配的重载。 - 冗余typename修饰:
TupleOfFunctions别名定义中,std::tuple<Func<Types>*...>不属于依赖模板参数的嵌套类型,不需要加typename前缀,严格模式下的编译器会将其识别为语法问题。 - 调用参数不合法:即使构造通过,后续调用时传入的字面量
1、临时字符串对象属于右值,无法绑定到lambda声明的非const左值引用参数,运行前编译就会报错。
最小修复可运行代码
#include <functional> #include <string> #include <iostream> template<typename... ArgTypes> class MyClass { public: template<typename Type> using Func = bool(Type const &); // 去掉冗余typename template<typename... Types> using TupleOfFunctions = std::tuple<Func<Types>*...>; TupleOfFunctions<ArgTypes...> _tuple; MyClass(TupleOfFunctions<ArgTypes...> t) : _tuple(t) { } }; int main(int argc, char** argv) { MyClass<int, std::string> M({ // lambda参数加const匹配签名 [](const int &arg) { return arg > 0; }, [](const std::string &arg) { return arg == "abc"; } }); std::cout << (*std::get<0>(M._tuple))(1); std::cout << (*std::get<1>(M._tuple))("xyz"); return 0; }
运行输出为10,符合预期。
无样板代码的通用函数式实现
如果要避免手动声明模板参数、支持带捕获的lambda等更多可调用对象,可以用C++17及以上版本的类模板实参推导(CTAD) 实现零样板的方案:
#include <tuple> #include <string> #include <iostream> #include <type_traits> template<typename... Callables> class FunctionTuple { private: std::tuple<Callables...> funcs; public: // 直接接收任意可调用对象,不需要提前声明参数类型 explicit FunctionTuple(Callables... c) : funcs(std::move(c)...) {} // 按索引调用对应函数 template<size_t Idx, typename... Args> decltype(auto) invoke(Args&&... args) const { return std::get<Idx>(funcs)(std::forward<Args>(args)...); } }; // 推导指引,自动推导可调用对象类型,不需要手动写模板参数 template<typename... Callables> FunctionTuple(Callables...) -> FunctionTuple<Callables...>; int main() { // 不需要手动指定模板参数,直接传lambda自动推导 auto M = FunctionTuple( [](const int &arg) { return arg > 0; }, [](const std::string &arg) { return arg == "abc"; }, // 支持带捕获的lambda,原函数指针方案不支持 [base = 10](int a) { return a + base; } ); std::cout << M.invoke<0>(1) << "\n"; std::cout << M.invoke<1>("xyz") << "\n"; std::cout << M.invoke<2>(5) << "\n"; return 0; }
该实现的优势:
- 无冗余样板:创建对象时不需要手动声明参数类型列表,自动推导传入的可调用对象类型
- 通用性强:支持无捕获lambda、带捕获lambda、函数对象、
std::function、普通函数指针等所有可调用类型 - 类型安全:所有参数匹配检查都在编译期完成,没有运行时开销
内容的提问来源于stack exchange,提问作者layer19
相关产品推荐
相关产品推荐

