C++ Concepts组合用作模板约束的跨编译器兼容问题
C++跨编译器兼容的Concept组合解决方案
问题背景
C++20中Concept无法完全当作类模板处理,组合Concept作为新模板约束时存在跨编译器兼容问题:需求代码在Visual Studio可正常运行,但在Clang/GCC中报错。
最初的IIterable Concept定义及验证代码如下,该版本在所有编译器中均可正常用于模板约束:
#include <ranges> #include <type_traits> #include <vector> #include <string> template <typename ITERABLE, typename OF_T> concept IIterable = std::ranges::range<ITERABLE> && std::is_convertible_v<std::ranges::range_value_t<ITERABLE>, OF_T>; static_assert(IIterable<std::vector<int>, int>); static_assert(IIterable<std::vector<long int>, int>); static_assert(IIterable<std::vector<int>, long int>); static_assert(!IIterable<std::vector<std::string>, int>); // 可迭代但元素无法转换为int
用于容器构造函数约束的示例:
template <typename T> struct Collection { template <IIterable<T> ITERABLE_OF_ADDABLE> Collection(ITERABLE_OF_ADDABLE&& src) { // 构造逻辑 } };
泛化尝试与报错问题
为泛化IIterable,定义了通用约束IIterableWith,意图实现“范围+元素满足自定义约束”的复用逻辑:
// 范围 + 元素满足指定谓词模板 template <typename ITERABLE, template <typename> typename ITEM_PREDICATE> concept IIterableWith = std::ranges::range<ITERABLE> && ITEM_PREDICATE<std::ranges::range_value_t<ITERABLE>>::value;
尝试通过Concept柯里化传入convertible_to实现元素约束,但所有编译器均不支持该写法:
template <typename ITERABLE, typename OF_T> concept IIterable1 = IIterableWith<ITERABLE, convertible_to<OF_T>>;
自行实现IsAddableOfT结构体适配模板参数:
template <typename T> struct IsAddableOfT { template <typename POTENTIALLY_ADDABLE_T> using Test = std::is_convertible<POTENTIALLY_ADDABLE_T, T>; };
但后续基于该结构体定义的IIterable仅在VS中正常,Clang/GCC报类型/值不匹配错误:
template <typename ITERABLE, typename OF_T> concept IIterable = IIterableWith<ITERABLE, typename IsAddableOfT<OF_T>::Test>;
错误信息:
type/value mismatch at argument 2 in template parameter list for 'template<class ITERABLE, template<class> class ITEM_PREDICATE> concept IIterableWith
期望的优雅Concept组合形式(当前标准不支持):
template <concept <typename>A, concept <typename>B> concept conjunction = A && B
跨编译器兼容解决方案
方案1:直接组合Concept(最简洁)
放弃模板模板参数的泛化,直接在目标Concept中组合所需约束,这是最通用且跨编译器的写法:
template <typename ITERABLE, typename OF_T> concept IIterable = std::ranges::range<ITERABLE> && std::convertible_to<std::ranges::range_value_t<ITERABLE>, OF_T>;
方案2:通用二元约束组合
如果需要复用“范围+二元约束”的逻辑,可定义接受二元Concept的通用Concept,实现约束复用:
// 通用:范围 + 元素与目标类型满足指定二元约束 template <typename R, typename U, template <typename, typename> typename BinaryConcept> concept RangeWithBinaryConstraint = std::ranges::range<R> && BinaryConcept<std::ranges::range_value_t<R>, U>; // 基于通用约束定义IIterable template <typename ITERABLE, typename OF_T> concept IIterable = RangeWithBinaryConstraint<ITERABLE, OF_T, std::convertible_to>; // 可扩展其他类似约束,比如元素类型完全匹配的范围 template <typename ITERABLE, typename OF_T> concept IterableOfSameType = RangeWithBinaryConstraint<ITERABLE, OF_T, std::is_same>;
方案3:绑定参数的一元Concept适配器
若需保留模板模板参数的一元Concept泛化能力,可通过结构体绑定目标类型生成适配的一元Concept:
// 通用:范围 + 元素满足指定一元约束 template <typename R, template <typename> typename UnaryConcept> concept RangeWithUnaryConstraint = std::ranges::range<R> && UnaryConcept<std::ranges::range_value_t<R>>; // 绑定目标类型的适配器,生成一元ConvertibleTo约束 template <typename U> struct ConvertibleToAdapter { template <typename T> concept type = std::convertible_to<T, U>; }; // 基于适配器定义IIterable template <typename ITERABLE, typename OF_T> concept IIterable = RangeWithUnaryConstraint<ITERABLE, ConvertibleToAdapter<OF_T>::template type>;
内容的提问来源于stack exchange,提问作者lewis
相关产品推荐
相关产品推荐

