【问题标题】:C++ concepts for template-values and parameter pack模板值和参数包的 C++ 概念
【发布时间】:2021-01-30 20:24:55
【问题描述】:

想知道对于parameters pack 上的concepts,什么语法最有效/最方便,包括当类型(ou 值的类型)相互依赖时的values template-parameters

例如,使用以下函数:

equal_v<values...> 在所有值相等时为真

template <auto... values>
constexpr static auto equal_v = []() consteval
{
    static_assert(sizeof...(values) > 0, "equal_v : no arguments");
    constexpr auto first_value = std::get<0>(std::tuple{values...});
    static_assert(
        (std::equality_comparable_with<decltype(values), decltype(first_value)> && ...),
        "equal_v : cannot compare values");
    return ((values == first_value) && ...);
}
();

我会的:

template <typename ... Ts>
concept are_equality_comparable = requires(Ts ... values)
{
    { 
        std::conditional_t<(std::equality_comparable_with<decltype(std::get<0>(std::tuple{values...})), decltype(values)> && ...), std::true_type, std::false_type>{}
    } -> std::same_as<std::true_type>;
};

template <auto ... values>
    requires(are_equality_comparable<decltype(values)...>)
constexpr static auto equal_v = []() consteval {
    static_assert(sizeof...(values) > 0, "equal_v : no arguments");
    constexpr auto first_value = std::get<0>(std::tuple{values...});
   
    return ((values == first_value) && ...); 
}();

这有点难看,使用std::conditional&lt;..., std::true_type, std::false_type&gt; 作为std::same_as&lt;..., std::true_type&gt; 参数。

所以我最终得到了以下语法,我认为这是最优雅的:

template <auto first_value, auto ... values>
    requires (std::equality_comparable_with<decltype(first_value), decltype(values)> && ...)
constexpr static auto equal_v = []() consteval {
    return ((values == first_value) && ...); 
}();

或者,第一个参数不是强制性的:

template <auto ... values>
    requires (std::equality_comparable_with<decltype(std::get<0>(std::tuple{values...})), decltype(values)> && ...)
constexpr static auto equal_v = []() consteval {
    return ((values == std::get<0>(std::tuple{values...})) && ...); 
}();

但是,由于所有值都取决于第一个值,
我还没有想出使用这种假设语法的方法:

template <auto first_value, std::equality_comparable_with<decltype(first_value)> ... values>
constexpr static auto equal_v = []() consteval {
    return ((values == first_value) && ...); 
}();

所以,这里有几点:

  • 是否有一种优雅的方式来使用概念来限制模板值的类型而不是模板类型参数?
  • 有没有办法限制模板参数包中相互依赖的类型而不修改函数签名,没有requires 子句? 例如 template &lt;auto ... values&gt; 而不是 template &lt;auto first_value, auto ... values&gt;

[编辑] 正如 cmets 中的 artyer 所指出的,concept auto value 是一种有效的语法。
此外,这不适用于 MSVC 19.28,因为它会导致:

错误 C7601:不满足关联的约束

也不是 GCC 10.2:

错误:不满足占位符约束

但适用于 Clang 11.0.1。

template <auto first_value, std::equality_comparable_with<decltype(first_value)> auto ... values> constexpr static auto equal_v = []() consteval {
   return ((values == first_value) && ...);
}();

[EDIT_2]

为了使equal_v&lt;&gt;为真:

template <auto first_value = int{}, std::equality_comparable_with<decltype(first_value)> auto ... values>
constexpr static auto equal_v = []() consteval {
   return ((values == first_value) && ...);
}();

【问题讨论】:

  • 对于你要找的最后一个template&lt;auto first_value, std::equalityy_comparable_with&lt;decltype(first_value)&gt; auto... values&gt;(完全一样,如果你想限制一个函数参数,你有concept auto name
  • 太棒了!非常感谢。如果我是对的,en.cppreference.com/w/cpp/language/constraints 上没有提到这种语法
  • 这工作正常,但如前所述,它使用 2 个模板参数而不是 1 个 cpp template &lt;auto first_value, std::equality_comparable_with&lt;decltype(first_value)&gt; auto ... values&gt; constexpr static auto equal_v = []() consteval { return ((values == first_value) &amp;&amp; ...); }();
  • 顺便说一句,equal_v&lt;&gt; 不是微不足道的true,而是一个错误,这是非常出乎意料的。
  • @Guss:它是P1141,尽管在 P0734 之前的原始提案版本中删除了一些模糊相似的语法。

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


【解决方案1】:

好吧,作为结论,以下是两个问题的答案:

  • 如何对模板值参数应用约束?

    @Artyer 和 @Davis Herring 指出,concept auto value 是在 p1141r2 中定义的合法语法。
    NB :目前不属于 cppreference 文档。

  • 当类型相互依赖时,如何对参数包应用约束?

    • 使用约束自动 (concept (auto) arg 语法) :

      用默认值定义第一个(以保留无参数分辨率)
      并在包含剩余参数的参数包上应用约束。

      template <auto first_value = int{}, 
                    std::equality_comparable_with<decltype(first_value)> auto ... values>
          constexpr static auto equal_v = []() consteval {
             return ((values == first_value) && ...);
          }();
      
    • 使用requires-clause 语法:

      template <auto ... values>
        requires (std::equality_comparable_with<
           decltype(std::get<0>(std::tuple{values...})),
           decltype(values)
        > && ...)
      constexpr static auto equal_v = []() consteval {
      return ((values == std::get<0>(std::tuple{values...})) && ...); 
      }();
      

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    相关资源
    最近更新 更多