【问题标题】:Idiomatic way to map a concept to a concrete type将概念映射到具体类型的惯用方式
【发布时间】:2021-07-30 09:37:30
【问题描述】:

给定一组 C++ 概念:

concept A = ...;
concept B = ...;
concept C = ...;

还有一组脚踏实地的非模板类型:

class ProcessA;
class ProcessB;
class ProcessC;

是否有一种惯用的方式来编写元函数get_matching_type,这样:

std::is_same_v<get_matching_type<TypeThatSatisfiesA>, ProcessA>;
std::is_same_v<get_matching_type<TypeThatSatisfiesB>, ProcessB>;
std::is_same_v<get_matching_type<TypeThatSatisfiesC>, ProcessC>;

全部成立?基本上,如何将 C++ 概念映射到 C++ 类型。

我看到的唯一简单方法是: 1/ 通过条件句的重叠,例如类似:

 using get_matching_type = std::conditional_t<A<T>, ProcessA, 
                              std::conditional_t<B<T>, ProcessB, 
                                std::conditional_t<C<T>, ProcessC>
                              >
                            >; 

但我想要一个不会使模板实例化深度超过屋顶的函数。

2/ 通过专业化:

template<A T>
struct get_matching_type<T> { using type = ProcessA; };
template<B T>
struct get_matching_type<T> { using type = ProcessB; };
template<C T>
struct get_matching_type<T> { using type = ProcessC; };

但是样板文件穿过屋顶:)

【问题讨论】:

  • 为什么需要这个?如果你的概念只匹配一种类型,那为什么它是一个概念呢?
  • 不,我的概念可以匹配任意数量的类型。例如:所有带有 { float 值的结构体; } 成员。但是对于满足这一点的所有类型(并且可能来自我之外的代码库),我可以应用一个实际操作。

标签: c++ c++20 c++-concepts


【解决方案1】:

“模式匹配”可以通过重载来完成:

template <TypeThatSatisfiesA T> ProcessA helper(T*);
template <TypeThatSatisfiesB T> ProcessB helper(T*);
template <TypeThatSatisfiesC T> ProcessC helper(T*);

template <typename T>
using get_matching_type = decltype(helper(std::declval<T*>()));

Demo

【讨论】:

    【解决方案2】:

    一个概念只不过是一个美化的布尔函数。您可以在给定参数的情况下评估函数,但对于给定函数,从根本上不可能有效地确定它在哪些参数处评估为true。做到这一点的唯一方法基本上是枚举所有可能的参数组合,并查看函数在每个组合中的计算结果。

    【讨论】:

      【解决方案3】:

      使用std::disjunction:

      template<bool V, class T>
      struct match : std::bool_constant<V> { using type = T; };
      
      template<class T>
      using get_matching_type = typename std::disjunction<
          match<A<T>, ProcessA>,
          match<B<T>, ProcessB>,
          match<C<T>, ProcessC>,
          std::false_type>::type;
      

      这是因为std::disjunction 返回(通过继承)它的第一个具有真值::value 的参数;它不必是std::bool_constant 的直接实例化,但可以保存其他数据。

      【讨论】:

        猜你喜欢
        • 2018-12-04
        • 2011-04-01
        • 2020-04-30
        • 2018-11-16
        • 2020-03-07
        • 1970-01-01
        • 2013-06-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多