我最近一直在尝试C++概念。我正在尝试以下“范围扩展”文档中的定义:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4569.pdf
Same的定义和用法让我感到困惑。由于我未知的原因,作者没有给出明确的定义。所以我正在使用:

template <class T, class U>
concept bool Same()
{
  return std::is_same<T, U>::value;
}

问题在于该文档为Assignable提供了以下定义:
template <class T, class U>
concept bool Assignable()
{
  return Common<T, U>() && requires(T&& a, U&& b) {
    { std::forward<T>(a) = std::forward<U>(b) } -> Same<T&>;
  };
}

它不起作用(在GCC 6.3中):一个简单的Assignable<int&, int&&>()概念检查为我提供了false(我已验证Common部分正常)。我必须将Same<T&>更改为T&才能使其正常工作。在其他一些地方也使用相同的Same<Type>检查。

我的问题是:
  • 我对Same的定义正确吗?
  • 为什么使用Same<T&>代替T&?有什么区别?

  • 谢谢你的帮助。

    最佳答案

    在周末解决问题之后,我想我自己找到了答案。

    Eric Niebler和Casey Carter对Same的定义更为精细,它支持多个模板参数(不只是两个),但是我的定义对于两个参数的情况基本上是正确的。

    使用-> Type时,目的是可以将方括号中的表达式隐式转换为Type。使用-> Same<Type>时,目的是使方括号中的表达式恰好是Type。因此它们是不同的。

    但是,有一个陷阱。约束检查非常复杂,甚至Eric和Casey之类的专家都犯了一个错误,并在N4569中给出了错误的定义。 Eric在GitHub上讨论了这个问题:

    https://github.com/ericniebler/stl2/issues/330

    如果按照N4569中的说明使用它,则意味着该表达式应该能够传递给想象的函数模板,例如

    template <typename U>
    f(U)
    requires Same<T&, U>()
    

    这不起作用-如果传入的表达式是T的左值,则推导的UT而不是T&。解决方案是在Same<T&>&&中使用Assignable。这将产生以下想象的功能模板:
    template <typename U>
    f(U&&)
    requires Same<T&, U>()
    

    现在一切正常,如果传入的表达式是T的左值,则必须将U推导为T&

    玩概念对我来说是一个好习惯,但是我可能应该更早找到它们的代码。它们在以下GitHub存储库中具有完整的概念集:

    https://github.com/CaseyCarter/cmcstl2

    对C++概念感兴趣的人应该研究一下。

    10-04 14:39