如何用tuple类型列表与std::constructible_from实现构造性检查?
问题描述
用tuple存储类型列表TypeList,需求是:给定类型X,检查TypeList中是否至少有一个类型可由X构造,且必须使用标准库概念std::constructible_from。
编写的概念定义如下:
template <typename From, typename To, std::size_t... Is> concept ConstructibleFromHelper = requires(From from, To to) { requires (std::constructible_from<typename std::tuple_element<Is, To>::type,From> || ...); }; template <typename From, typename To> concept ConstructibleFrom = requires { requires ConstructibleFromHelper<From,To,std::make_index_sequence<std::tuple_size_v<To>>()>; };
编译时报错:
./type_traits.h:36:46: error: template argument for non-type template parameter is treated as function type 'std::make_index_sequence<std::tuple_size_v<To>> ()' (aka '__make_integer_seq<std::integer_sequence, unsigned long, std::tuple_size_v<To>> ()') requires ConstructibleFromHelper<From,To,std::make_index_sequence<std::tuple_size_v<To>>()>;
核心问题是无法直接将make_index_sequence展开为std::size_t... Is参数包,且概念不支持偏特化,需要调整实现方式。
解决方案
方法一:通过辅助概念推导参数包
错误根源是直接把std::make_index_sequence<...>()当作模板参数传递,这会被解析为函数类型而非参数包。正确的做法是传递std::index_sequence实例让编译器推导参数包:
#include <concepts> #include <tuple> #include <utility> template <typename From, typename ToTuple, std::size_t... Is> concept ConstructibleFromHelper = (std::constructible_from<std::tuple_element_t<Is, ToTuple>, From> || ...); template <typename From, typename ToTuple> concept AnyConstructibleFromTuple = requires { requires ConstructibleFromHelper<From, ToTuple, std::make_index_sequence<std::tuple_size_v<ToTuple>>::type{}>; };
这里使用std::make_index_sequence<...>::type{}生成std::index_sequence<Is...>的实例,编译器会自动推导出参数包Is...,进而展开折叠表达式检查每个tuple元素的构造性。
方法二:紧凑实现(无需辅助概念)
利用立即调用的lambda表达式直接处理索引序列,代码更简洁:
#include <concepts> #include <tuple> template <typename From, typename ToTuple> concept AnyConstructibleFromTuple = []<std::size_t... Is>(std::index_sequence<Is...>) { return (std::constructible_from<std::tuple_element_t<Is, ToTuple>, From> || ...); }(std::make_index_sequence<std::tuple_size_v<ToTuple>>{});
lambda表达式通过模板参数推导接收索引序列,内部用折叠表达式遍历tuple的所有类型,检查是否存在可由From构造的类型。
验证代码
struct A {}; struct B { B(A) {} }; struct C {}; using TypeList = std::tuple<A, B, C>; static_assert(AnyConstructibleFromTuple<A, TypeList>); // 成立:A可构造自身,B可由A构造 static_assert(!AnyConstructibleFromTuple<B, TypeList>); // 不成立:A、C都无法由B构造
内容的提问来源于stack exchange,提问作者Debashish
相关产品推荐
相关产品推荐

