如何定义递归概念?

16

cppreference.com中指出:

概念(concept)不能递归地引用自身

但是我们如何定义一个概念,代表整数、整数向量,或整数向量的向量等。

我可以有如下内容:

template < typename Type > concept bool IInt0 = std::is_integral_v<Type>;
template < typename Type > concept bool IInt1 = IInt0<Type> || requires(Type tt) { {*std::begin(tt)} -> IInt0; };
template < typename Type > concept bool IInt2 = IInt1<Type> || requires(Type tt) { {*std::begin(tt)} -> IInt1; };

static_assert(IInt2<int>);
static_assert(IInt2<std::vector<int>>);
static_assert(IInt2<std::vector<std::vector<int>>>);

但我希望有类似于 IIntX 的东西,可以表示任何N的IIntN

这种可能吗?


2
我很好奇你想将这个概念应用到哪些代码上。如何编写能够以相同方式操作整数和向量的代码,而不使用大量的 if constexpr 或等效代码,这最终会使整个概念失去意义?确实,你应该非常仔细地考虑在概念中使用 || 的情况。 - Nicol Bolas
@NicolBolas 对于 || 来说,支持无限嵌套的容器是很困难的。 - Yakk - Adam Nevraumont
2
@Yakk-AdamNevraumont 我认为指针更...你的算法是什么,可以对intvector<vector<vector<int>>>都有意义的执行某些操作? - Barry
1
@Barry 这不难吧?我的意思是,“递增每个整数”对两者都有意义。自动解包单子(或操作其内容)即使需要任意下降,也不是疯狂的行为。在我看来,自动装箱才是疯狂的;反过来,特别是在单个操作上,是可以接受的。 - Yakk - Adam Nevraumont
@Yakk-AdamNevraumont:也许更合理的用例是一个函数概念,它接受一系列范围并将其展平。从逻辑上讲,这样的东西应该能够任意地向下穿越每个内部范围的value_type,直到找到一个非范围的东西,并且所有各种范围都必须同意相同的value_type。但是没有办法在概念中轻松表达这一点。或者至少,不用去做可怕的、非概念的事情。 - Nicol Bolas
这只是我选择的一个简单示例,用来说明这个问题。当然,让我发布这个问题的真实世界问题是另一个。 - Vahagn
1个回答

20

概念总是可以参考类型特征:

template <typename T> concept C = some_trait<T>::value;

这种特性可以递归使用:

template <typename T>
struct some_trait : std::false_type { };

template <std::Integral T>
struct some_trait<T> : std::true_type { };

template <typename T, typename A>
struct some_trait<std::vector<T, A>> : some_trait<T> { };

如果您不仅仅是指vector,那么最后一个部分特化可以泛化为:

template <std::Range R>
struct some_trait<R> : some_trait<std::range_value_t<R>> { };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接