如何对C++ Lambda的每个数据成员执行static_assert检查?
检查Lambda所有数据成员是否可平凡复制的实现方案
要实现对Lambda每个数据成员的static_assert检查,核心思路是利用Lambda闭包类型在C++17及以后属于聚合体的特性,通过模板元编程遍历其所有成员,逐一验证是否满足可平凡复制的要求。
第一步:完善可平凡复制的判断工具
直接用标准库的std::is_trivially_copyable比自定义has_trivial_copy更通用,也可以基于它封装:
#include <type_traits> template<typename T> constexpr bool has_trivial_copy_v = std::is_trivially_copyable_v<T>;
第二步:实现聚合体成员遍历的元编程工具
我们需要一个能递归遍历聚合体所有成员的模板,在编译期对每个成员执行检查:
namespace detail { // 递归终止:无剩余成员时返回true template<typename Aggregate, std::size_t... Is> constexpr bool check_all_members_impl(const Aggregate&, std::index_sequence<Is...>) { return (has_trivial_copy_v<std::tuple_element_t<Is, decltype(std::make_tuple(std::declval<Aggregate>()))>> && ...); } } // 对外接口:检查聚合体所有成员是否都可平凡复制 template<typename Aggregate> constexpr bool all_members_trivially_copyable() { // 生成成员索引序列,适配聚合体的成员数量 return detail::check_all_members_impl(std::declval<Aggregate>(), std::make_index_sequence<std::tuple_size_v<decltype(std::make_tuple(std::declval<Aggregate>()))>>{}); }
第三步:对Lambda执行编译期检查
有两种方式可以触发检查:
方式1:定义Lambda时自动绑定检查
写一个辅助模板,把Lambda包装起来的同时触发static_assert:
template<typename Func> constexpr auto make_trivial_copyable_lambda(Func&& func) { static_assert(all_members_trivially_copyable<std::decay_t<Func>>(), "所有Lambda捕获成员必须是可平凡复制的!"); return std::forward<Func>(func); } // 使用示例 int main() { int i = 0; std::string str; // 编译通过:捕获的int是可平凡复制的 auto lambda1 = make_trivial_copyable_lambda([i]{}); // 编译失败:std::string不可平凡复制,触发static_assert auto lambda2 = make_trivial_copyable_lambda([i, str]{}); }
方式2:直接对已有Lambda类型检查
如果已经有了Lambda对象,也可以直接针对其类型做检查:
auto lambda2 = [i, str]{}; static_assert(all_members_trivially_copyable<decltype(lambda2)>(), "成员不可平凡复制");
关键说明
- 这个方案依赖C++17的结构化绑定与聚合体特性,以及折叠表达式(
&& ...)来遍历所有成员的检查结果。 - 对于C++20及以后,还可以用
std::is_aggregate_v先判断类型是否为聚合体,避免对非聚合体类型误操作。
内容的提问来源于stack exchange,提问作者Nathanael Weiss
相关产品推荐
相关产品推荐

