CRTP和递归定义概念

huangapple go评论75阅读模式
英文:

CRTP and recursively defining a concept

问题

有关此问题已经有了一些问题(例如 https://stackoverflow.com/questions/40853060/c-concepts-crtp ),但据我所知,答案并没有真正解决根本问题的方法。

我想要递归地定义一个概念。大致如下。如果一个类型是整数,那么它就是 concept_0 的模型。如果一个类型是 concept_n 元素的范围,那么它就是 concept_{n+1} 的模型。我希望以下类似的代码能够编译通过:

template <typename R>
concept my_object = std::integral<R> || (std::ranges::sized_range<R> && my_object<typename R::value_type>);

有办法实现这个吗?

英文:

There are questions already regarding this (eg. https://stackoverflow.com/questions/40853060/c-concepts-crtp) but afaict the answers do not really say how to solve the underlying issue.

I want to define recursively a concept. Something along the following lines. A type models concept_0 if it is integral. And a type models concept_{n+1} if it is a range of concept_n elements. I would like something like the following to compile

template &lt;typename R&gt;
concept my_object = std::integral&lt;R&gt; || (std::ranges::sized_range&lt;R&gt; &amp;&amp; my_object&lt;typename R::value_type&gt;);

Is there a way to achieve this?

答案1

得分: 4

AFAIK, concepts do not allow recursion. But templates do, so to get your example to work, you could write a template class that models your concept and then just define your concept as a thin wrapper around that:

template <typename R>
struct my_object : std::false_type
{};

// specialization for integral types
template <std::integral R>
struct my_object<R>
 : public std::true_type
{};

// specialization for ranges using recursion
template <std::ranges::sized_range R>
struct my_object<R>
 : public std::conditional_t<
    my_object<typename R::value_type>::value,
    std::true_type, 
    std::false_type
>
{};

// wrapping in a concept
template <typename R>
concept my_object_concept = my_object<R>::value;

链接至示例

英文:

AFAIK, concepts do not allow recursion. But templates do, so to get your example to work, you could write a template class that models your concept and then just define your concept as a thin wrapper around that:

template &lt;typename R&gt;
struct my_object : std::false_type
{};

// specialization for integral types
template &lt;std::integral R&gt;
struct my_object&lt;R&gt;
 : public std::true_type
{};

// specialization for ranges using recursion
template &lt;std::ranges::sized_range R&gt;
struct my_object&lt;R&gt;
 : public std::conditional_t&lt;
    my_object&lt;typename R::value_type&gt;::value,
    std::true_type, 
    std::false_type
&gt;
{};

// wrapping in a concept
template &lt;typename R&gt;
concept my_object_concept = my_object&lt;R&gt;::value;

https://godbolt.org/z/1fqKzrYGh

答案2

得分: 3

请看老式的方法:

#include <concepts>
#include <ranges>
#include <vector>

template <typename R> 
struct is_my_object
{
  static constexpr bool value = false;
};

template <std::integral R>
  struct is_my_object<R>
  {
    static constexpr bool value = true;
  };

template <std::ranges::sized_range R>
  struct is_my_object<R>
  {
    static constexpr bool value = is_my_object<typename R::value_type>::value;
  };

template <typename R>
concept my_object = is_my_object<R>::value;

static_assert(my_object<int>);
static_assert(!my_object<float>);
static_assert(my_object<std::vector<int>>);
static_assert(my_object<std::vector<std::vector<int>>>);

(This definition will fail on `my_object<int[2]>`; fixing this problem is an easy exercise).
英文:

Do it the old-fashioned way:

#include &lt;concepts&gt;
#include &lt;ranges&gt;
#include &lt;vector&gt;

template &lt;typename R&gt; 
  struct is_my_object
  {
    static constexpr bool value = false;
  };

template &lt;std::integral R&gt;
  struct is_my_object&lt;R&gt;
  {
    static constexpr bool value = true;
  };

template &lt;std::ranges::sized_range R&gt;
  struct is_my_object&lt;R&gt;
  {
    static constexpr bool value = is_my_object&lt;typename R::value_type&gt;::value;
  };

template &lt;typename R&gt;
concept my_object = is_my_object&lt;R&gt;::value;

static_assert(my_object&lt;int&gt;);
static_assert(!my_object&lt;float&gt;);
static_assert(my_object&lt;std::vector&lt;int&gt;&gt;);
static_assert(my_object&lt;std::vector&lt;std::vector&lt;int&gt;&gt;&gt;);

(This definition will fail on my_object&lt;int[2]&gt;; fixing this problem is an easy exercise).

答案3

得分: 1

你的类型特征实际上不需要三个模板定义来实现这个概念,因为只有两种情况要处理。此外,使用 std::ranges::range_value_t<R> 而不是 typename R::value_type 允许你检查 C 风格数组类型。

#include <concepts>
#include <ranges>
#include <type_traits>
#include <vector>

template <class R>
struct is_my_object : std::is_integral<R> {};

template <std::ranges::sized_range R>
struct is_my_object<R> : is_my_object<std::ranges::range_value_t<R>> {};

template <class R>
concept my_object = is_my_object<R>::value;

static_assert(my_object<int>);
static_assert(not my_object<float>);
static_assert(my_object<std::vector<int>>);
static_assert(my_object<std::vector<std::vector<int>>>);
static_assert(my_object<int[2]>);
static_assert(not my_object<int[]>);

https://godbolt.org/z/5Krb6cosv

英文:

Your type trait doesn't actually need three template definitions in order to implement this concept, since there's only two cases to handle. Also, using std::ranges::range_value_t&lt;R&gt; instead of typename R::value_type allows you to check C-style array types as well.

#include &lt;concepts&gt;
#include &lt;ranges&gt;
#include &lt;type_traits&gt;
#include &lt;vector&gt;

template &lt;class R&gt;
struct is_my_object : std::is_integral&lt;R&gt; {};

template &lt;std::ranges::sized_range R&gt;
struct is_my_object&lt;R&gt; : is_my_object&lt;std::ranges::range_value_t&lt;R&gt;&gt; {};

template &lt;class R&gt;
concept my_object = is_my_object&lt;R&gt;::value;

static_assert(my_object&lt;int&gt;);
static_assert(not my_object&lt;float&gt;);
static_assert(my_object&lt;std::vector&lt;int&gt;&gt;);
static_assert(my_object&lt;std::vector&lt;std::vector&lt;int&gt;&gt;&gt;);
static_assert(my_object&lt;int[2]&gt;);
static_assert(not my_object&lt;int[]&gt;);

https://godbolt.org/z/5Krb6cosv

huangapple
  • 本文由 发表于 2023年6月19日 19:39:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76506257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定