能否在C++ Concept中使用std::index_sequence且无需手动编写参数包?
实现带详细错误提示的std::variant全类型可转int的Concept
你可以结合std::index_sequence自动展开std::variant的备选类型,同时利用现代C++编译器对Concept折叠表达式的错误定位支持,既不用手动写参数包,又能得到明确的错误提示——GCC 12+、Clang 14+这类编译器已经能在折叠的约束检查失败时,精准指出哪个类型不满足要求。
具体实现方式
1. 先定义单个类型的转换检查Concept
#include <variant> #include <concepts> // 检查单个类型是否能转换为int template<typename T> concept ConvertibleToInt = std::convertible_to<T, int>;
2. 定义针对std::variant的全局检查Concept
利用std::variant_size_v获取备选类型数量,自动生成索引序列,再通过折叠表达式逐个验证每个备选类型:
// 辅助Concept:接收variant类型和索引序列,展开检查每个备选类型 template<typename Variant, std::size_t... Is> concept AllVariantTypesConvertibleImpl = (ConvertibleToInt<std::variant_alternative_t<Is, Variant>> && ...); // 对外暴露的Concept:自动生成索引序列并调用辅助检查 template<typename Variant> concept AllVariantTypesConvertibleToInt = AllVariantTypesConvertibleImpl<Variant, std::make_index_sequence<std::variant_size_v<Variant>>>;
测试与错误提示示例
当传入包含不可转换类型的variant时:
void process(AllVariantTypesConvertibleToInt auto&& var) {} int main() { // 这里的std::string无法转换为int,会触发约束失败 std::variant<int, std::string, float> bad_var; process(bad_var); return 0; }
用GCC编译时,错误提示会直接点明问题:
error: no matching function for call to 'process(std::variant<int, std::__cxx11::basic_string<char>, float>&)' note: candidate: 'template<class auto:1> requires AllVariantTypesConvertibleToInt<decltype(bad_var)> void process(auto:1&&)' note: constraints not satisfied note: within 'template<class Variant> concept bool AllVariantTypesConvertibleToInt<Variant>' note: within 'template<class Variant, long unsigned int ...Is> concept bool AllVariantTypesConvertibleImpl<Variant, Is...>' note: 'ConvertibleToInt<std::__cxx11::basic_string<char>>' evaluated to false
另一种简化写法(利用std::variant的types成员)
C++20里std::variant<Ts...>自带types成员,它是一个std::tuple<Ts...>类型。我们可以先定义针对tuple的检查Concept,再复用给variant:
// 检查tuple中所有类型是否可转换为int template<typename Tuple> concept TupleAllConvertibleToInt = false; template<typename... Ts> concept TupleAllConvertibleToInt<std::tuple<Ts...>> = (ConvertibleToInt<Ts> && ...); // 针对variant的检查Concept template<typename Variant> concept VariantAllConvertibleToInt = TupleAllConvertibleToInt<typename Variant::types>;
这种写法的错误提示同样清晰,编译器会直接指出tuple中哪个类型不满足转换要求。
内容的提问来源于stack exchange,提问作者LHLaurini
相关产品推荐
相关产品推荐

