问题描述
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、但是回到这个问题,这里为什么不能使用引用传参数呢。我还是没有搞明白。
。。。。。。