c++ - 为什么 'std::tie' d 对象的结构化绑定(bind)失败?

标签 c++ iterator c++17 structured-bindings std-tie

我很好奇做this asked 通过以下方式解决问题:

#include <iostream>
#include <set>
#include <iterator>
#include <array>
#include <tuple>
#include <type_traits>

int main()
{
    const std::set<int> s{ 0, 1, 2, 3, 4, 5, 6, 7, 8 };
    auto iter = s.find(5);
    using IterType = decltype(iter);

    // using `std::array` works fine!
    const auto& [pv1, nxt1] = std::array<IterType, 2>{std::prev(iter), std::next(iter)};
    std::cout <<"using std::array<IterType, 2> :"<< *pv1 << " " << *nxt1 << '\n'; // prints: 4 6

    // using ` std::make_tuple` works fine!
    const auto& [pv2, nxt2] = std::make_tuple(std::prev(iter), std::next(iter));
    std::cout << "using std::make_tuple :" << *pv2 << " " << *pv2 << '\n';        // prints: 4 6

    // using `std::tie` deduction happens in MSVC, but not in GCC and Clang
    const auto& [pv3, nxt3] = std::tie(std::prev(iter), std::next(iter));
    // following is an assertion failure in MSVC with /O2  /std:c++17
    std::cout << "using std::tie :" << *pv3 << " " << *nxt3<< '\n';
}

std::tie d 返回了 std::prevstd::next 的迭代器,并允许 进行自动推导的结构化绑定(bind)。

const auto& [pv3, nxt3] = std::tie(std::prev(iter), std::next(iter));

看起来它允许的唯一编译器是 MSVC v19.14 with /O2/std:c++17! GCC 9.1clang 8.0 不同意这一点。在在线编译器中看到:https://godbolt.org/z/DTb_OZ

海湾合作委员会说:

<source>:23:28: error: no matching function for call to 'tie'
        const auto& [pv3, nxt3] = std::tie(std::prev(iter), std::next(iter));
                                  ^~~~~~~~
/opt/compiler-explorer/gcc-8.3.0/lib/gcc/x86_64-linux-gnu/8.3.0/../../../../include/c++/8.3.0/tuple:1605:5: note: candidate function [with _Elements = <std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>>] not viable: expects an l-value for 1st argument
    tie(_Elements&... __args) noexcept
^

clang 说:

<source>: In function 'int main()':
<source>:23:46: error: cannot bind non-const lvalue reference of type 'std::_Rb_tree_const_iterator<int>&' to an rvalue of type 'std::_Rb_tree_const_iterator<int>'
   23 |  const auto& [pv3, nxt3] = std::tie(std::prev(iter), std::next(iter));
      |                                     ~~~~~~~~~^~~~~~
In file included from <source>:5:
/opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/tuple:1611:19: note:   initializing argument 1 of 'constexpr std::tuple<_Elements& ...> std::tie(_Elements& ...) [with _Elements = {std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>}]'
 1611 |     tie(_Elements&... __args) noexcept
      |         ~~~~~~~~~~^~~~~~~~~~

查看 cppreference.com 中给出的示例 MSVC 是正确的吗?或者谁在这里,为什么?

有趣的是在运行

std::cout << "using std::tie :" << *pv3 << " " << *nxt3<< '\n';

给我

enter image description here

(在 MSVS 2019 中,/std:c++17)

最佳答案

根据 [tuple.creation]/tie :

template<class... TTypes>
  constexpr tuple<TTypes&...> tie(TTypes&... t) noexcept;

这里,参数是非常量左值引用。 std::prev(iter)std::next(iter) 不能绑定(bind)到左值引用,因此代码应该被拒绝。 comment 中解释了 MSVC 接受它的原因。 :

Enable /Za flag to compiler, then the code will be refused. MVSC [sic] has extenstion which allows to bind temps to Lvalue reference. tie gets Lvalue references, but prev, next returns temporary. – rafix07 2019-07-25 07:52:58Z

关于c++ - 为什么 'std::tie' d 对象的结构化绑定(bind)失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57196890/

相关文章:

c++ - 函数未声明(首次使用此函数)

c++ - 在嵌套类中使用模板值

c++ - tbb:concurrent_hash_map<K,V>:英特尔线程构建模块 (TBB) 的示例代码

c++ - 在 C++17 中使用 <filesystem> 成员链接错误

c++ - 不使用 FOR/WHILE 循环逐行读取文件

c++ - 请求 'print'中的成员 'y',非类类型

c++ - 如何检查字符串是否是另一个字符串的真子集

c++ - 使用迭代器从字符串中删除特殊字符

ruby - 在 ruby​​ 1.8.6 (each_char) 中遍历字符串的每个字符

c++ - 在 GCC 8 上工作的 Constexpr 计数器,并且不限于命名空间范围