C++实例化类模板传入lambda作为构造参数该使用什么模板参数?
C++类模板构造结合lambda的编译问题解答
编译失败的核心原因
- 类模板实参推导的版本限制。C17标准才引入*类模板实参推导(CTAD)*特性,允许编译器根据构造函数传入的实参自动推导类模板的参数类型。你写的
BigStruct main_struct{[](const SmallStruct&) {}}这种省略模板参数的写法,在C17之前的标准下是不支持的,必须显式指定模板参数。 - 手动指定的模板参数类型不匹配。你传给构造函数的实参是lambda对象,它的类型是编译器为每个lambda单独生成的匿名类型,和
SmallStruct没有直接关系,所以你指定T为SmallStruct/SmallStruct&都和构造函数入参的类型不匹配,编译必然失败。
对应的解决方案
方案1:使用C++17及以上标准编译
如果你的编译器支持C++17,只需要在编译时开启对应标准即可:
- gcc/clang 编译器添加编译参数
std=c++17 - Visual Studio 在项目属性中把C标准版本调整为C17或更高
开启后你的原始代码可以直接编译通过,编译器会自动推导T为传入的lambda的匿名类型。
方案2:显式指定正确的模板参数(兼容C++11/14)
如果需要兼容旧标准,你需要明确指定T和传入的lambda类型匹配,有两种常用实现方式:
方式A:用std::function包装lambda
把可调用对象包装成std::function,显式指定对应的函数签名作为模板参数:
#include <functional> struct SmallStruct {}; template <typename T> struct BigStruct { BigStruct(const T& arg) : arg{arg} {}; private: const T& arg; }; int main() { // 模板参数指定为和lambda签名匹配的std::function类型 BigStruct<std::function<void(const SmallStruct&)>> main_struct{[](const SmallStruct&) {}}; }
方式B:用decltype获取lambda类型
先把lambda存入变量,用decltype获取它的类型作为模板参数:
struct SmallStruct {}; template <typename T> struct BigStruct { BigStruct(const T& arg) : arg{arg} {}; private: const T& arg; }; int main() { auto my_lambda = [](const SmallStruct&) {}; // 用decltype推导lambda的类型作为模板参数 BigStruct<decltype(my_lambda)> main_struct{my_lambda}; }
额外注意:悬空引用风险
你当前的BigStruct的成员变量是const T& arg,属于左值引用。如果你向构造函数传入临时lambda对象(比如原始代码中直接写在构造函数大括号内的lambda就是临时对象),这个临时对象在构造语句执行完成后就会被销毁,BigStruct内部存储的引用会变成悬空引用,后续访问会触发未定义行为。如果需要长期持有这个可调用对象,建议把成员变量修改为值类型T arg,避免引用悬空。
内容的提问来源于stack exchange,提问作者Lachlan
相关产品推荐
相关产品推荐

