在 C++ 中是否可以使用命名变量(例如键和值)而不是 .first 和 .second 进行 std::map<> "for element : container" 迭代?
Is it possible in C++ to do std::map<> "for element : container" iteration with named variables (eg, key and value) instead of .first and .second?
我不确定要搜索什么。
我找到了 Renaming first and second of a map iterator 但这不是我想要做的。
这就是我想要做的事情 [参见下面的无意义 C++ 代码]。有可能接近这个吗?否则我想只需要选择 "adapting" 迭代器作为循环内的第一行。
// what I want to do:
std::map<int, std::string> my_map;
// ... populate my_map
for(auto key, auto & value: my_map){
// do something with integer key and string value
}
C++11 很好,但如果可能,最好避免使用 boost。
我得到的最接近的是
// TODO, can this be templated?
struct KeyVal{
int & id;
std::string & info;
template <typename P>
KeyVal(P & p)
: id(p.first)
, info(p.second)
{
}
};
//...
for ( KeyVal kv : my_map ){
std::cout << kv.info;
}
但这意味着要为每个地图编写一个适配器 class :(
// slightly joke answer/"what could possibly go wrong?"
#define key first
#define value second
受以下 Barry 启发的一种方法是编写一个范围适配器。
在没有 boost
或类似库支持的情况下执行此操作很痛苦,但是:
编写范围模板。它存储 2 class iterator
s 并具有 begin()
和 end()
方法(以及您想要的任何其他方法)。
编写一个转换迭代器适配器。它接受一个迭代器,并将其包装起来,以便它的值类型由某个函数对象 F.
转换
编写一个 to_kv
转换器,它接受一个 std::pair<K, V> cv&
和 return 一个 struct kv_t { K cv& key; V cv& value; }
。
将 3 接 2 接 1 并命名为 as_kv
。它需要一个范围的对,returns 一个范围的键值。
您最终得到的语法是:
std::map<int, std::string> m;
for (auto kv : as_kv(m)) {
std::cout << kv.key << "->" << kv.value << "\n";
}
这很好。
这是一个极简主义的解决方案,实际上并没有创建合法的迭代器,但确实支持 for(:)
:
template<class Key, class Value>
struct kv_t {
Key&& key;
Value&& value;
};
// not a true iterator, but good enough for for(:)
template<class Key, class Value, class It>
struct kv_adapter {
It it;
void operator++(){ ++it; }
kv_t<Key const, Value> operator*() {
return {it->first, it->second};
}
friend bool operator!=(kv_adapter const& lhs, kv_adapter const& rhs) {
return lhs.it != rhs.it;
}
};
template<class It, class Container>
struct range_trick_t {
Container container;
range_trick_t(Container&&c):
container(std::forward<Container>(c))
{}
It begin() { return {container.begin()}; }
It end() { return {container.end()}; }
};
template<class Map>
auto as_kv( Map&& m ) {
using std::begin;
using iterator = decltype(begin(m)); // no extra (())s
using key_type = decltype((begin(m)->first)); // extra (())s on purpose
using mapped_type = decltype((begin(m)->second)); // extra (())s on purpose
using R=range_trick_t<
kv_adapter<key_type, mapped_type, iterator>,
Map
>;
return R{std::forward<Map>(m)};
}
std::map<int, std::string> m() { return {{0, "Hello"}, {2, "World"}}; }
这是非常最小的,但有效。我一般不会鼓励这种半评估的伪迭代器用于 for(:)
循环;使用真正的迭代器只是一个适度的额外成本,以后不会让人们感到惊讶。
(现在有临时映射支持。不支持平面 C 数组...但是)
范围技巧存储一个容器(可能是一个引用),以便将临时容器复制到在 for(:)
循环期间存储的对象中。 Container
类型的非临时容器是某种类型的 Foo&
,因此它不会制作冗余副本。
另一方面,kv_t
显然只存储引用。可能有一个奇怪的迭代器 returning 临时对象的情况会破坏这个 kv_t
实现,但我不确定如何在不牺牲更常见情况下的性能的情况下通常避免它。
如果您不喜欢上面的 kv.
部分,我们可以做一些解决方案,但它们不是那么干净。
template<class Map>
struct for_map_t {
Map&& loop;
template<class F>
void operator->*(F&& f)&&{
for (auto&& x:loop) {
f( decltype(x)(x).first, decltype(x)(x).second );
}
}
};
template<class Map>
for_map_t<Map> map_for( Map&& map ) { return {std::forward<Map>(map)}; }
然后:
map_for(m)->*[&](auto key, auto& value) {
std::cout << key << (value += " ") << '\n';
};
够接近了吧?
有一些关于 first-class 元组(和因此对)的建议可能会给你类似的东西,但我不知道这些建议的状态。
如果进入 C++,您可能最终得到的语法如下所示:
for( auto&& [key, value] : container )
对上述 ->*
憎恶的评论:
所以 ->*
被用作来自 Haskell 的 operator bind
(连同隐式元组解包),我们正在为它提供一个 lambda 来获取包含的数据在地图内,return无效。 (Haskell-esque) return 类型成为 void(无)上的映射,我将其省略为 void。
技术有问题:你失去了 break;
和 continue;
,这很糟糕。
一个不太受 hackkey Haskell 启发的变体会期望 lambda return 类似于 void | std::experimental::expected<break_t|continue_t, T>
,如果 T
是 void
return 没什么,如果 T
是一个元组类型 return 一个映射,如果 T
是一个映射加入 returned 映射类型。它还会根据 lambda 想要的内容(SFINAE 样式检测)解压或不解压包含的元组。
但这对于 SO 答案来说有点过分了;这篇题外话指出,上述编程风格并不是一个完全的死胡同。然而,它在 C++ 中是非常规的。
您可以编写一个 class 模板:
template <class K, class T>
struct MapElem {
K const& key;
T& value;
MapElem(std::pair<K const, T>& pair)
: key(pair.first)
, value(pair.second)
{ }
};
优点是可以写成key
和value
,缺点是必须指定类型:
for ( MapElem<int, std::string> kv : my_map ){
std::cout << kv.key << " --> " << kv.value;
}
如果 my_map
是 const
,那也行不通。您必须执行以下操作:
template <class K, class T>
struct MapElem {
K const& key;
T& value;
MapElem(std::pair<K const, T>& pair)
: key(pair.first)
, value(pair.second)
{ }
MapElem(const std::pair<K const, std::remove_const_t<T>>& pair)
: key(pair.first)
, value(pair.second)
{ }
};
for ( MapElem<int, const std::string> kv : my_map ){
std::cout << kv.key << " --> " << kv.value;
}
一团糟。现在最好的事情就是习惯于编写 .first
和 .second
并希望结构化绑定提案通过,这将允许您真正想要的东西:
for (auto&& [key, value] : my_map) {
std::cout << key << " --> " << value;
}
最接近它使用的东西std::tie
:
std::map<int, std::string> my_map;
int key;
std::string value;
for(auto&& p: my_map)
{
std::tie(key, value) = p;
std::cout << key << ": " << value << std::endl;
}
当然不能将表达式放在 for range 循环中,因此可以使用宏来允许表达式:
#define FOREACH(var, cont) \
for(auto && _p:cont) \
if(bool _done = false) {} \
else for(var = std::forward<decltype(_p)>(_p); !_done; _done = true)
那么std::tie
可以直接在循环中使用:
std::map<int, std::string> my_map;
int key;
std::string value;
FOREACH(std::tie(key, value), my_map)
{
std::cout << key << ": " << value << std::endl;
}
只是为了提供另一种方法几乎做你想做的事,我前段时间写了这篇文章以避免.first
和.second
在我的代码中:
auto pair2params = [](auto&& f)
{
return [f](auto&& p) {
f(p.first, p.second);
};
};
现在你可以这样写(假设基于范围 for_each
):
int main()
{
auto values = map<int, string>{
{0, "hello"},
{1, "world!"}
};
for_each(values, pair2params([](int key, const string& value) {
cout << key << ": " << value << "\n";
});
}
运行 示例:http://ideone.com/Bs9Ctm
我通常更喜欢 KISS 方法:
template<typename KeyValuePair>
typename KeyValuePair::first_type& key(KeyValuePair& kvp)
{
return kvp.first;
}
template<typename KeyValuePair>
const typename KeyValuePair::first_type& key(const KeyValuePair& kvp)
{
return kvp.first;
}
template<typename KeyValuePair>
void key(const KeyValuePair&& kvp) = delete;
template<typename KeyValuePair>
typename KeyValuePair::second_type& value(KeyValuePair& kvp)
{
return kvp.second;
}
template<typename KeyValuePair>
const typename KeyValuePair::second_type& value(const KeyValuePair& kvp)
{
return kvp.second;
}
template<typename KeyValuePair>
void value(const KeyValuePair&& kvp) = delete;
使用示例如下:
for(auto& kvp : my_map) {
std::cout << key(kvp) << " " << value(kvp) << "\n";
}
在Apache Mesos中,我们使用了一个叫做foreachpair
的宏,可以这样使用:
foreachpair (const Key& key, const Value& value, elems) {
/* ... */
}
您当然可以将 Key
和 Value
替换为 auto
,以及您想在此处使用的任何限定符。它还支持 break
和 continue
.
我的最新实现如下所示:
#define FOREACH_PREFIX BOOST_PP_CAT(foreach_, __LINE__)
#define FOREACH_BODY BOOST_PP_CAT(FOREACH_PREFIX, _body__)
#define FOREACH_BREAK BOOST_PP_CAT(FOREACH_PREFIX, _break__)
#define FOREACH_CONTINUE BOOST_PP_CAT(FOREACH_PREFIX, _continue__)
#define FOREACH_ELEM BOOST_PP_CAT(FOREACH_PREFIX, _elem__)
#define FOREACH_ONCE BOOST_PP_CAT(FOREACH_PREFIX, _once__)
上面的宏通过包含 __LINE__
数字为 foreachpair
宏中使用的各种组件提供唯一名称。
1 #define foreachpair(KEY, VALUE, ELEMS) \
2 for (auto&& FOREACH_ELEM : ELEMS) \
3 if (false) FOREACH_BREAK: break; /* set up the break path */ \
4 else if (bool FOREACH_CONTINUE = false) {} /* var decl */ \
5 else if (true) goto FOREACH_BODY; /* skip the loop exit checks */ \
6 else for (;;) /* determine whether we should break or continue. */ \
7 if (!FOREACH_CONTINUE) goto FOREACH_BREAK; /* break */ \
8 else if (true) break; /* continue */ \
9 else \
10 FOREACH_BODY: \
11 if (bool FOREACH_ONCE = false) {} /* var decl */ \
12 else for (KEY = std::get<0>( \
13 std::forward<decltype(FOREACH_ELEM)>(FOREACH_ELEM)); \
14 !FOREACH_ONCE; FOREACH_ONCE = true) \
15 for (VALUE = std::get<1>( \
16 std::forward<decltype(FOREACH_ELEM)>(FOREACH_ELEM)); \
17 !FOREACH_CONTINUE; FOREACH_CONTINUE = true)
我将逐行介绍。
- (混乱的开始)。
- 基于范围的 for 循环遍历
ELEMS
。
- 我们设置了标签
FOREACH_BREAK
。我们跳转到这个标签到 break
跳出这个循环。
- 我们设置了控制流标志
FOREACH_CONTINUE
。如果当前迭代正常退出,则为 true
,或者通过 continue
退出,如果当前迭代通过 break
. 退出,则为 false
- 我们总是跳转到下面的
FOREACH_BODY
标签。
- 这是我们拦截控制流并检查
FOREACH_CONTINUE
标志以确定我们如何退出当前迭代的地方。
- 如果
FOREACH_CONTINUE
是 false
,我们知道我们是通过 break
退出的,所以我们跳转到 FOREACH_BREAK
。
- 否则,
FOREACH_CONTINUE
是 true
,我们 break
跳出 for (;;)
循环,进入下一次迭代。
- (混乱中途)。
- 我们总是从(5)跳到这里。
- 设置
FOREACH_ONCE
仅用于执行 for
循环,该循环声明 KEY
恰好一次。
- 声明
KEY
.
- 正确转发元素。
- 使用
FOREACH_ONCE
确保这个循环恰好执行一次。
- 声明
VALUE
.
- 正确转发元素。
- 使用
FOREACH_CONTINUE
来确保这个循环恰好执行一次,并表明循环是否通过break
退出。
注意:使用std::get
也允许支持从序列中出现的std::tuple
或std::array
。例如,std::vector<std::tuple<int, int>>
对于现代 c++17,现在可以使用 structured bindings。
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {
map<int, string> my_map;
my_map[0] = "hello";
my_map[1] = "world";
for (auto&& [key, value] : my_map) {
cout << key << "," << value << "\n";
}
return 0;
}
构建它:
$ clang++ -std=c++17 test.cpp -o program
输出:
$ ./program
0,hello
1,world
我不确定要搜索什么。 我找到了 Renaming first and second of a map iterator 但这不是我想要做的。
这就是我想要做的事情 [参见下面的无意义 C++ 代码]。有可能接近这个吗?否则我想只需要选择 "adapting" 迭代器作为循环内的第一行。
// what I want to do:
std::map<int, std::string> my_map;
// ... populate my_map
for(auto key, auto & value: my_map){
// do something with integer key and string value
}
C++11 很好,但如果可能,最好避免使用 boost。
我得到的最接近的是
// TODO, can this be templated?
struct KeyVal{
int & id;
std::string & info;
template <typename P>
KeyVal(P & p)
: id(p.first)
, info(p.second)
{
}
};
//...
for ( KeyVal kv : my_map ){
std::cout << kv.info;
}
但这意味着要为每个地图编写一个适配器 class :(
// slightly joke answer/"what could possibly go wrong?"
#define key first
#define value second
受以下 Barry 启发的一种方法是编写一个范围适配器。
在没有 boost
或类似库支持的情况下执行此操作很痛苦,但是:
编写范围模板。它存储 2
class iterator
s 并具有begin()
和end()
方法(以及您想要的任何其他方法)。编写一个转换迭代器适配器。它接受一个迭代器,并将其包装起来,以便它的值类型由某个函数对象 F.
转换
编写一个
to_kv
转换器,它接受一个std::pair<K, V> cv&
和 return 一个struct kv_t { K cv& key; V cv& value; }
。将 3 接 2 接 1 并命名为
as_kv
。它需要一个范围的对,returns 一个范围的键值。
您最终得到的语法是:
std::map<int, std::string> m;
for (auto kv : as_kv(m)) {
std::cout << kv.key << "->" << kv.value << "\n";
}
这很好。
这是一个极简主义的解决方案,实际上并没有创建合法的迭代器,但确实支持 for(:)
:
template<class Key, class Value>
struct kv_t {
Key&& key;
Value&& value;
};
// not a true iterator, but good enough for for(:)
template<class Key, class Value, class It>
struct kv_adapter {
It it;
void operator++(){ ++it; }
kv_t<Key const, Value> operator*() {
return {it->first, it->second};
}
friend bool operator!=(kv_adapter const& lhs, kv_adapter const& rhs) {
return lhs.it != rhs.it;
}
};
template<class It, class Container>
struct range_trick_t {
Container container;
range_trick_t(Container&&c):
container(std::forward<Container>(c))
{}
It begin() { return {container.begin()}; }
It end() { return {container.end()}; }
};
template<class Map>
auto as_kv( Map&& m ) {
using std::begin;
using iterator = decltype(begin(m)); // no extra (())s
using key_type = decltype((begin(m)->first)); // extra (())s on purpose
using mapped_type = decltype((begin(m)->second)); // extra (())s on purpose
using R=range_trick_t<
kv_adapter<key_type, mapped_type, iterator>,
Map
>;
return R{std::forward<Map>(m)};
}
std::map<int, std::string> m() { return {{0, "Hello"}, {2, "World"}}; }
这是非常最小的,但有效。我一般不会鼓励这种半评估的伪迭代器用于 for(:)
循环;使用真正的迭代器只是一个适度的额外成本,以后不会让人们感到惊讶。
(现在有临时映射支持。不支持平面 C 数组...但是)
范围技巧存储一个容器(可能是一个引用),以便将临时容器复制到在 for(:)
循环期间存储的对象中。 Container
类型的非临时容器是某种类型的 Foo&
,因此它不会制作冗余副本。
另一方面,kv_t
显然只存储引用。可能有一个奇怪的迭代器 returning 临时对象的情况会破坏这个 kv_t
实现,但我不确定如何在不牺牲更常见情况下的性能的情况下通常避免它。
如果您不喜欢上面的 kv.
部分,我们可以做一些解决方案,但它们不是那么干净。
template<class Map>
struct for_map_t {
Map&& loop;
template<class F>
void operator->*(F&& f)&&{
for (auto&& x:loop) {
f( decltype(x)(x).first, decltype(x)(x).second );
}
}
};
template<class Map>
for_map_t<Map> map_for( Map&& map ) { return {std::forward<Map>(map)}; }
然后:
map_for(m)->*[&](auto key, auto& value) {
std::cout << key << (value += " ") << '\n';
};
够接近了吧?
有一些关于 first-class 元组(和因此对)的建议可能会给你类似的东西,但我不知道这些建议的状态。
如果进入 C++,您可能最终得到的语法如下所示:
for( auto&& [key, value] : container )
对上述 ->*
憎恶的评论:
所以 ->*
被用作来自 Haskell 的 operator bind
(连同隐式元组解包),我们正在为它提供一个 lambda 来获取包含的数据在地图内,return无效。 (Haskell-esque) return 类型成为 void(无)上的映射,我将其省略为 void。
技术有问题:你失去了 break;
和 continue;
,这很糟糕。
一个不太受 hackkey Haskell 启发的变体会期望 lambda return 类似于 void | std::experimental::expected<break_t|continue_t, T>
,如果 T
是 void
return 没什么,如果 T
是一个元组类型 return 一个映射,如果 T
是一个映射加入 returned 映射类型。它还会根据 lambda 想要的内容(SFINAE 样式检测)解压或不解压包含的元组。
但这对于 SO 答案来说有点过分了;这篇题外话指出,上述编程风格并不是一个完全的死胡同。然而,它在 C++ 中是非常规的。
您可以编写一个 class 模板:
template <class K, class T>
struct MapElem {
K const& key;
T& value;
MapElem(std::pair<K const, T>& pair)
: key(pair.first)
, value(pair.second)
{ }
};
优点是可以写成key
和value
,缺点是必须指定类型:
for ( MapElem<int, std::string> kv : my_map ){
std::cout << kv.key << " --> " << kv.value;
}
如果 my_map
是 const
,那也行不通。您必须执行以下操作:
template <class K, class T>
struct MapElem {
K const& key;
T& value;
MapElem(std::pair<K const, T>& pair)
: key(pair.first)
, value(pair.second)
{ }
MapElem(const std::pair<K const, std::remove_const_t<T>>& pair)
: key(pair.first)
, value(pair.second)
{ }
};
for ( MapElem<int, const std::string> kv : my_map ){
std::cout << kv.key << " --> " << kv.value;
}
一团糟。现在最好的事情就是习惯于编写 .first
和 .second
并希望结构化绑定提案通过,这将允许您真正想要的东西:
for (auto&& [key, value] : my_map) {
std::cout << key << " --> " << value;
}
最接近它使用的东西std::tie
:
std::map<int, std::string> my_map;
int key;
std::string value;
for(auto&& p: my_map)
{
std::tie(key, value) = p;
std::cout << key << ": " << value << std::endl;
}
当然不能将表达式放在 for range 循环中,因此可以使用宏来允许表达式:
#define FOREACH(var, cont) \
for(auto && _p:cont) \
if(bool _done = false) {} \
else for(var = std::forward<decltype(_p)>(_p); !_done; _done = true)
那么std::tie
可以直接在循环中使用:
std::map<int, std::string> my_map;
int key;
std::string value;
FOREACH(std::tie(key, value), my_map)
{
std::cout << key << ": " << value << std::endl;
}
只是为了提供另一种方法几乎做你想做的事,我前段时间写了这篇文章以避免.first
和.second
在我的代码中:
auto pair2params = [](auto&& f)
{
return [f](auto&& p) {
f(p.first, p.second);
};
};
现在你可以这样写(假设基于范围 for_each
):
int main()
{
auto values = map<int, string>{
{0, "hello"},
{1, "world!"}
};
for_each(values, pair2params([](int key, const string& value) {
cout << key << ": " << value << "\n";
});
}
运行 示例:http://ideone.com/Bs9Ctm
我通常更喜欢 KISS 方法:
template<typename KeyValuePair>
typename KeyValuePair::first_type& key(KeyValuePair& kvp)
{
return kvp.first;
}
template<typename KeyValuePair>
const typename KeyValuePair::first_type& key(const KeyValuePair& kvp)
{
return kvp.first;
}
template<typename KeyValuePair>
void key(const KeyValuePair&& kvp) = delete;
template<typename KeyValuePair>
typename KeyValuePair::second_type& value(KeyValuePair& kvp)
{
return kvp.second;
}
template<typename KeyValuePair>
const typename KeyValuePair::second_type& value(const KeyValuePair& kvp)
{
return kvp.second;
}
template<typename KeyValuePair>
void value(const KeyValuePair&& kvp) = delete;
使用示例如下:
for(auto& kvp : my_map) {
std::cout << key(kvp) << " " << value(kvp) << "\n";
}
在Apache Mesos中,我们使用了一个叫做foreachpair
的宏,可以这样使用:
foreachpair (const Key& key, const Value& value, elems) {
/* ... */
}
您当然可以将 Key
和 Value
替换为 auto
,以及您想在此处使用的任何限定符。它还支持 break
和 continue
.
我的最新实现如下所示:
#define FOREACH_PREFIX BOOST_PP_CAT(foreach_, __LINE__)
#define FOREACH_BODY BOOST_PP_CAT(FOREACH_PREFIX, _body__)
#define FOREACH_BREAK BOOST_PP_CAT(FOREACH_PREFIX, _break__)
#define FOREACH_CONTINUE BOOST_PP_CAT(FOREACH_PREFIX, _continue__)
#define FOREACH_ELEM BOOST_PP_CAT(FOREACH_PREFIX, _elem__)
#define FOREACH_ONCE BOOST_PP_CAT(FOREACH_PREFIX, _once__)
上面的宏通过包含 __LINE__
数字为 foreachpair
宏中使用的各种组件提供唯一名称。
1 #define foreachpair(KEY, VALUE, ELEMS) \
2 for (auto&& FOREACH_ELEM : ELEMS) \
3 if (false) FOREACH_BREAK: break; /* set up the break path */ \
4 else if (bool FOREACH_CONTINUE = false) {} /* var decl */ \
5 else if (true) goto FOREACH_BODY; /* skip the loop exit checks */ \
6 else for (;;) /* determine whether we should break or continue. */ \
7 if (!FOREACH_CONTINUE) goto FOREACH_BREAK; /* break */ \
8 else if (true) break; /* continue */ \
9 else \
10 FOREACH_BODY: \
11 if (bool FOREACH_ONCE = false) {} /* var decl */ \
12 else for (KEY = std::get<0>( \
13 std::forward<decltype(FOREACH_ELEM)>(FOREACH_ELEM)); \
14 !FOREACH_ONCE; FOREACH_ONCE = true) \
15 for (VALUE = std::get<1>( \
16 std::forward<decltype(FOREACH_ELEM)>(FOREACH_ELEM)); \
17 !FOREACH_CONTINUE; FOREACH_CONTINUE = true)
我将逐行介绍。
- (混乱的开始)。
- 基于范围的 for 循环遍历
ELEMS
。 - 我们设置了标签
FOREACH_BREAK
。我们跳转到这个标签到break
跳出这个循环。 - 我们设置了控制流标志
FOREACH_CONTINUE
。如果当前迭代正常退出,则为true
,或者通过continue
退出,如果当前迭代通过break
. 退出,则为 - 我们总是跳转到下面的
FOREACH_BODY
标签。 - 这是我们拦截控制流并检查
FOREACH_CONTINUE
标志以确定我们如何退出当前迭代的地方。 - 如果
FOREACH_CONTINUE
是false
,我们知道我们是通过break
退出的,所以我们跳转到FOREACH_BREAK
。 - 否则,
FOREACH_CONTINUE
是true
,我们break
跳出for (;;)
循环,进入下一次迭代。 - (混乱中途)。
- 我们总是从(5)跳到这里。
- 设置
FOREACH_ONCE
仅用于执行for
循环,该循环声明KEY
恰好一次。 - 声明
KEY
. - 正确转发元素。
- 使用
FOREACH_ONCE
确保这个循环恰好执行一次。 - 声明
VALUE
. - 正确转发元素。
- 使用
FOREACH_CONTINUE
来确保这个循环恰好执行一次,并表明循环是否通过break
退出。
false
注意:使用std::get
也允许支持从序列中出现的std::tuple
或std::array
。例如,std::vector<std::tuple<int, int>>
对于现代 c++17,现在可以使用 structured bindings。
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {
map<int, string> my_map;
my_map[0] = "hello";
my_map[1] = "world";
for (auto&& [key, value] : my_map) {
cout << key << "," << value << "\n";
}
return 0;
}
构建它:
$ clang++ -std=c++17 test.cpp -o program
输出:
$ ./program
0,hello
1,world