【问题标题】:C++20: Concepts of multiple types and its constraint, correct syntax?C++20:多种类型的概念及其约束,正确的语法?
【发布时间】:2019-11-20 15:19:58
【问题描述】:

确认在即将发布的c++20标准中,根据最近的Cologne ISO C++ Meeting中的this reddit report,我们将能够指定模板的concept,并且对于每个类/函数模板,我们将能够在其类型上设置constraints。但是,在文档和教程(例如here)中,我找不到多类型用例的正确语法。


假设我们有一个多类型概念:

template<typename T1, typename T2>
concept AreEqComparable = requires(T1 a, T2 b) {
    { a == b } -> bool;
};

假设,我想在两种不同类型之间定义一个简单的比较函数。 我该怎么做?更具体地说,我应该在下面代码的??? 部分写什么:

???
bool are_equal(T1 a, T2 b) { return a == b; }

我在herehere 甚至here 中找不到任何关于此案例的参考。我随机尝试了类似的东西:

/* 1 */ template<AreEqComparable T1, T2>
/* 2 */ AreEqComparable<T1, T2>
/* 3 */ template<AreEqComparable<T1, T2>>

但它们都抛出语法错误。我认为答案应该在 Bjarne Stroustrup 的规范 P0557 中的某个地方,但我快速浏览后无法找到它。

【问题讨论】:

  • 我没用过概念但是你试过template&lt;AreEqComparable T1, AreEqComparable T2&gt;吗?另外IsEqComparable 可能是一个更好的名称(因为它只适用于一个参数)。
  • @Galik 刚才试过了,不行。

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


【解决方案1】:

你可以这样写:

template <typename T1, typename T2>
    requires AreEqComparable<T1, T2>
bool are_equal(T1 a, T2 b)
{
    // ...
}

这里,我们使用 requires-clause 对类型模板参数施加要求。

【讨论】:

  • 谢谢,这行得通(我正在使用在线编译器wandbox)。有没有更简洁的写法?我的意思是在template 子句中,不必明确指定requires ...?
  • @FalconUA 我们可以写成template &lt;typename T1, AreEqComparable&lt;T1&gt; T2&gt;,但这有细微的不同——它实际上是AreEqComparable&lt;T2, T1&gt;。我真的不知道更紧凑的版本。
  • @FalconUA,TS 最初有 AreEqComparable{T1, T2} bool are_equal(…);,但没有等效的简写形式将其放入 C++20。
【解决方案2】:

你可以写:

template <typename T1, AreEqComparable<T1> T2>
bool are_equal(T1, T2);

这相当于:

template <typename T1, typename T2>
    requires AreEqComparable<T2, T1>
bool are_equal(T1, T2);

类型在此处的约束中被翻转,AreEqComparable&lt;T2, T1&gt; 而不是AreEqComparable&lt;T1, T2&gt;。这对于许多概念来说肯定很重要,但可能不是这个特别重要,因为== 本身在 C++20 中变得对称(缺少实际代码中不应该存在的病态案例)。如果你想真的确定这种对称性是有效的,你总是可以在概念中明确说明(EqualityComparableWith 在工作草案中):

template<typename T1, typename T2>
concept AreEqComparable = requires(T1 a, T2 b) {
    { a == b } -> bool;
    { b == a } -> bool;
};

您实际上可以通过翻转模板参数的顺序(h/t Matthieu M.)以正确的顺序获得所需的约束:

template <typename T2, AreEqComparable<T2> T1>
bool are_equal(T1, T2);

【讨论】:

  • template &lt;typename T1, AreEqComparable&lt;T1&gt; T2&gt; 这真的是正确的语法吗?看起来有点不对劲:O 我期待像template &lt;typename T1, AreEqComparable&lt;T1, T2&gt;&gt;
  • @ruohola 是的,没错。我们正在引入具有部分概念 ID AreEqComparable&lt;T1&gt; 的类型 T2。我不知道其他语法会如何引入T2
  • 那为什么不写template &lt;typename T2, AreEqComparable&lt;T2&gt; T1&gt; bool are_equal(T1, T2)呢?你会以正确的顺序得到参数......
  • @MatthieuM。哦耶。你可以这样做。
  • 感谢您的深入解释!
【解决方案3】:

另一种完全避免引入模板参数的语法(以添加其他冗余为代价):

bool are_equal(auto x,auto y)
  requires AreEqComparable<decltype(x),decltype(y)>
  {return x==y;}

【讨论】:

  • 哇,有什么规定可以把requires声明放在哪里吗?
  • @FalconUA:在template&lt;…&gt;R f(…) 之后——当然,仅适用于后一种情况下的函数,它们甚至不需要是模板(例如,它们可以是类模板的成员)。
  • 有趣的是,如果您使用class 并将参数命名为XY,这比普通模板声明短了整整两个字符:-)(82 对 84)
  • @Barry:当然——但另一个可能会有所改进,所以我需要保险!
  • @L.F.:是的;甚至析构函数也可以被约束,并且您可以拥有多个这样的 prospective 析构函数。
【解决方案4】:

在 GCC 8.2.0 中,概念应该写成这样:

concept bool ConceptName = /* ... */

但是C++ Templates: The Complete Guide 没有提到bool。由于C++20标准没有发布,很难说哪个是对的。

对于需要一个参数(不一定是类型)的概念,有一个速记:

template <UnaryConceptName T>

对于那些需要两个或更多参数的,没有简写:

template <typename T1, typename T2> requires BinaryConceptName<T1, T2>

typename 可以替换为特定的类型名称。

顺便说一句:

  1. 我上面提到的这本书对概念进行了简要介绍。

  2. 在 GCC 中使用 -fconcepts 来启用概念。

【讨论】:

  • concept bool 是概念 TS 中的语法。 C++20 将只是 concept
猜你喜欢
  • 1970-01-01
  • 2021-07-12
  • 1970-01-01
  • 1970-01-01
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多