关于在lambda的参数列表里不能传一个pair的引用

问题描述

template <typename Key, typename Value, typename F>
void update(std::map<Key, Value>& m, F foo) {
    std::for_each(m.begin(), m.end(), [&foo](typename std::pair<Key, Value>& p){p.second = foo(p.first);});   //不能编译通过

    std::for_each(m.begin(), m.end(), [&foo](typename std::pair<Key, Value> p) {p.second = foo(p.first);});    //可以编译通过
}

1、最开始的问题,只用一行代码,完成下面的一个功能

#include <iostream>
#include <map>
#include <string>
#include <tuple>
#include <functional>
#include <algorithm>

template <typename Key, typename Value, typename F>
void update(std::map<Key, Value>& m, F foo) {
    //todo
}

int main(int argc, const char *argv[])
{
    std::map<std::string, long long int> m {{"a", 1}, {"b", 2}, {"c", 3}};
    update(m, [](std::string key) {return std::hash<std::string>{}(key);});
    for(auto& k : m)
        std::cout << k.first << ":" << k.second << std::endl;
    return 0;
}

1.1、最开始我是这么想的,不知算不算一行呢。

for(auto& p : m) p.second = foo(p.first);

1.2、后来在一个帖子上看到如下代码

vector<string> words{"helo", "world", "this", "is", "C++11"};
ostringstream os;
char c = ' ';
for_each(words.begin(), words.end(), [&os, c](const string & s){os << s << c;} );

1.3、我便想到,我的那个代码其实就是想遍历一下map,然后处理每一个元素,那for_each不就可以吗,而且肯定算是一行代码,然后就有了下面的代码

std::for_each(m.begin(), m.end(), [&foo](std::map<Key, Value>::iterator& p) {p->second = foo(p->first);});

可是编译不过,仔细思考了一下,这里不应该用迭代器的,for_each是遍历的容器,把其存储的元素传给后面的方法,对于map来说因该是pair,

同时,还有另外一个错误,在模版里边,需要加typename,于是改成下面的样子

std::for_each(m.begin(), m.end(), [&foo](typename std::pair<Key, Value>& p) {p.second = foo(p.first);});

这次依然编译不过,但是,如果不是引用传参,像下面这样,就可以编译通过,可是这样功能就不对了

std::for_each(m.begin(), m.end(), [&foo](typename std::pair<Key, Value> p) {p.second = foo(p.first);});

1.4、进一步引申,发现单纯定义一个pair的引用也是不能编译通过的,像下面这样

std::pair<std::string, long long int>& p = *m.begin();  //不能编译通过
std::pair<std::string, long long int> p1 = *m.begin();  //可以编译通过


auto& ty = *m.begin();                                  //可以编译通过

这个时候,我就好奇了,为什么这里不能使用引用。

然后,我还发现迭代器也不能这样用

std::map<std::string, long long int>::iterator& it = m.begin();  //不能编译通过
std::map<std::string, long long int>::iterator it1 = m.begin();  //可以编译通过

但是,迭代器是可以改变原map里元素的值的,这是迭代器的使命。

 

1.5、通过查找资料,我发现了如下两种曲线救国的方法,

使用auto,但是得使用-std=c++14

std::for_each(m.begin(), m.end(), [&foo](auto& p) {p.second = foo(p.first);});  //编译的时候加-std=c++14

使用std::map<Key, Value>::value_type

std::for_each(m.begin(), m.end(), [&foo](typename std::map<Key, Value>::value_type& p) {p.second = foo(p.first);});

1.6、但是回到这个问题,这里为什么不能使用引用传参数呢。我还是没有搞明白。

。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值