当您使用 '++' 递增 std::vector<int>::iterator 时,它的类型是否会改变?

Dav*_*ard 6 c++ stdvector c++-concepts c++20

我正在尝试 C++20 概念,但遇到了一个无法解释的奇怪问题。

\n

我正在尝试定义一个concept检查给定迭代器是否可以递增(很好)的方法,并且还检查类型是否因此而改变(不好)。

\n

原谅我的无知,我错过了什么?错误的最后一行指出:

\n

\' 注意:\xe2\x80\x98++ it\xe2\x80\x99 不满足返回类型要求\n{ ++it } -> std::same_as; \'

\n
#include <functional>\n#include <vector>\n\ntemplate<typename Iter>\nconcept Iterable = requires(Iter it){\n    { ++it } // Check iterator can be incremented (compiles but does not check return type)\n    { ++it } -> std::same_as<Iter>; // Also check the return type (**fails**)\n};\n\ntemplate<typename Iter>\nrequires Iterable<Iter>\nvoid doesNothing(Iter current, Iter end){\n    while(current != end){\n        ++current;\n    }\n};\n\nint main(){\n    std::vector<int> v = {1, 2, 3};\n    doesNothing(v.begin(), v.end());\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

预先非常感谢您。

\n

我期待这一行:

\n
#include <functional>\n#include <vector>\n\ntemplate<typename Iter>\nconcept Iterable = requires(Iter it){\n    { ++it } // Check iterator can be incremented (compiles but does not check return type)\n    { ++it } -> std::same_as<Iter>; // Also check the return type (**fails**)\n};\n\ntemplate<typename Iter>\nrequires Iterable<Iter>\nvoid doesNothing(Iter current, Iter end){\n    while(current != end){\n        ++current;\n    }\n};\n\nint main(){\n    std::vector<int> v = {1, 2, 3};\n    doesNothing(v.begin(), v.end());\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

将“管道”返回{++it}到模板中,std::same_as<T, U>结果是std::same_as<std::vector<int>::iterator, std::vector<int>::iterator>当然会被接受。

\n

编辑:巴里的出色回答与此相关: Why does decltype(auto) return a reference here?

\n

Bar*_*rry 13

我期待这一行:

{ ++it } -> std::same_as<Iter>;
Run Code Online (Sandbox Code Playgroud)

将返回“管道”{++it}到模板中std::same_as<T, U>,结果std::same_as<std::vector<int>::iterator, std::vector<int>::iterator>当然会被接受。

你说对了一半。

的含义{ ++it } -> std::same_as<Iter>是我们正在检查这++it是一个有效的表达式并且std::same_as<decltype((++it)), Iter>成立,这是正确的。

decltype((+it))事实并非如此Iter。它是Iter&。这就是你的检查失败的原因。

这就是为什么std::weakly_incrementable指定为:

template<class I>
  concept weakly_incrementable =
    movable<I> &&
    requires(I i) {
      typename iter_difference_t<I>;
      requires is-signed-integer-like<iter_difference_t<I>>;
      { ++i } -> same_as<I&>;   // not required to be equality-preserving
      i++;                      // not required to be equality-preserving
    };
Run Code Online (Sandbox Code Playgroud)

  • @DaveWoodward 在这种情况下,额外的括号并不重要,“decltype(++it)”和“decltype((++it))”都是相同的 - 它们给你“Iter&amp;”。它们的不同之处在于表达式只是变量的名称。在这种情况下,“decltype(it)”是“Iter”,而“decltype((it))”是“Iter&amp;”(因为它是左值)。 (2认同)