使用Lambda完美配对对秒

问题描述

为什么此代码段无法编译?

flask.redirect@H_502_4@

使用gcc的错误是:

#include <iostream>
#include <vector>
#include <ranges>
#include <unordered_map>

namespace vw = std::ranges::views;

int main()
{
    auto get_second = [](auto&& pair) constexpr noexcept -> decltype(auto)
                      { return std::forward<decltype(pair)>(pair).second; };
    
    std::unordered_map<unsigned,std::pair<double,char> > m = {{5,{0.,'a'}}};
    

    for (auto& [d,c] : m | vw::transform(get_second))
        c = 'b';

    for (auto const& pair : m)
        std::printf("(%u,(%.3f,%c))\n",pair.first,pair.second.first,pair.second.second);
}
@H_502_4@

main.cpp: In function 'int main()': main.cpp:16:53: error: cannot bind non-const lvalue reference of type 'std::pair<double,char>&' to an rvalue of type 'std::__success_type<std::pair<double,char> >::type' {aka 'std::pair<double,char>'} 16 | for (auto& [d,c] : m | vw::transform(get_second)) | ^ @H_502_4@不能解决-> decltype(auto)@H_502_4@吗?如果我将std::pair<double,char>&@H_502_4@替换为-> decltype(auto)@H_502_4@,它将按预期工作。

解决方法

-> decltype(auto)不能评估为std::pair<double,char>&吗?

不。这是一个简单得多的示例:

struct X {
    int i;
};

X x{42};
decltype(auto) i = x.i;

iint还是int&?这是intdecltype(auto)通过将decltype(...)应用于右侧来派生其类型。 decltype(x.i)只是为您提供成员的类型,即int

要获取int&,您必须执行以下操作:

decltype(auto) i = (x.i);

因为现在,我们将类型设为decltype((x.i)),它产生int&

decltype有一个special rule用于非括号访问-因此添加括号可以避开它。这就是decltype(x.i)decltype((x.i))可以不同的原因。一旦我们回避了那个,在类型为decltype的左值上的T就会产生类型为T&的类型。 x.i是类型int的左值,因此我们得到int&

请注意,我说的可以有所不同,而必须则不同,如果成员i的类型为int&,则两个{{1 }}和decltype(x.i)将是decltype((x.i))


回到原始示例,您可以选择对返回的表达式加括号(并删除不必要的int&):

constexpr

或者只是知道因为我们正在进行类成员访问,所以它永远不会成为prvalue,因此我们可以简化为使用auto get_second = [](auto&& pair) noexcept -> decltype(auto) { return (FWD(pair).second); }; (不需要其他括号):

auto&&

标准库本身也提供了以下简称:

auto get_second = [](auto&& pair) noexcept -> auto&&
                  { return FWD(pair).second; };

您可以改写:

for (auto& [d,c] : m | vw::transform(get_second))

(如果需要其他元素,也可以使用for (auto& [d,c] : m | vw::values)


最后,视图名称空间的简称通常是elements<1>(而不是rv)。或只使用vw