首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用lambda实现pair.second的完美转发

利用lambda实现pair.second的完美转发
EN

Stack Overflow用户
提问于 2020-09-03 19:04:19
回答 1查看 172关注 0票数 2

为什么这个片段不编译?

代码语言:javascript
复制
#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);
}

使用gcc的错误是:

代码语言:javascript
复制
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))
      |                                                     ^

-> decltype(auto)不应该决心要std::pair<double, char>&吗?如果我用-> decltype(auto)代替-> std::pair<double, char>&,它就会像预期的那样工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-03 19:09:43

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

不是的。下面是一个简单得多的例子:

代码语言:javascript
复制
struct X {
    int i;
};

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

iint还是int&?这是一个intdecltype(auto)通过将decltype(...)应用到右侧来导出它的类型.decltype(x.i)只给出成员的类型,即int

为了获得一个int&,您必须这样做:

代码语言:javascript
复制
decltype(auto) i = (x.i);

因为现在我们得到了decltype((x.i))类型,它生成int&

decltype有一个用于非括号大小的访问的特殊规则 --所以添加括号会避开它。这就是为什么decltype(x.i)decltype((x.i))可能有所不同的原因。一旦我们避开了这个问题,decltypeT类型的值就会产生T&类型。x.i是一个int类型的值,所以我们得到了int&

注意,我说过可以不同而不一定不同,如果成员iint&类型的,那么decltype(x.i)decltype((x.i))都是int&

回到最初的示例,您可以选择使用括号调整返回的表达式(并删除不必要的constexpr):

代码语言:javascript
复制
auto get_second = [](auto&& pair) noexcept -> decltype(auto)
                  { return (FWD(pair).second); };

或者仅仅知道因为我们正在进行类成员访问,这永远不是一个prvalue,所以我们可以简化为使用auto&& (不需要额外的括号):

代码语言:javascript
复制
auto get_second = [](auto&& pair) noexcept -> auto&&
                  { return FWD(pair).second; };

此外,标准库本身也提供了这方面的缩写:

代码语言:javascript
复制
for (auto& [d, c] : m | vw::transform(get_second))

相反,你可以写:

代码语言:javascript
复制
for (auto& [d, c] : m | vw::values)

(也可以是elements<1>,以防您需要其他元素)。

最后,视图命名空间的短名称的典型选择是rv (而不是vw)。或者只使用views

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63730124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档