C ++概念相同且可分配

时间:2017-03-18 03:53:51

标签: c++ c++-concepts

我最近一直在尝试C ++概念。我正在尝试以下Ranges Extensions文档中的定义:

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&?有什么区别?

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

在周末攻击问题后,我想我已经找到了答案。

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 ++概念感兴趣的人应该研究它。

答案 1 :(得分:4)

Same定义的问题有点微妙:Ranges TS要求实现将约束Same<T, U>()视为等同于Same<U, T>(),即识别&的对称性#34; TU&#34;:

的类型相同
template <class T, class U>
requires Same<T, U>()
void foo(); // #1

template <class T, class U>
requires Same<U, T>()
void foo(); // redeclaration of #1

template <class T>
requires Same<int, T>()
void bar(); // #2

template <class T>
requires Same<T, int>()
void bar(); // redeclaration of #2

这种等价性不能用语言表达,因为约束规范化的规则可以识别以下各项:

is_same_v<T, U>
is_same_v<U, T>
is_same_v<T, int>
is_same_v<int, T>

作为不同的原子约束。这需要通过编译器内在实现Same