C++ 在C++;要执行std::map<&燃气轮机&引用;对于元素:“容器”;使用命名变量(如键和值)而不是.first和.second进行迭代?
我不知道该找什么。 我发现了,但这不是我想做的 这是我想做的[参见下面的“无意义C++代码”)。有可能发生类似的事情吗?否则,我只需要选择“调整”迭代器作为循环中的第一行C++ 在C++;要执行std::map<&燃气轮机&引用;对于元素:“容器”;使用命名变量(如键和值)而不是.first和.second进行迭代?,c++,c++11,dictionary,iteration,readability,C++,C++11,Dictionary,Iteration,Readability,我不知道该找什么。 我发现了,但这不是我想做的 这是我想做的[参见下面的“无意义C++代码”)。有可能发生类似的事情吗?否则,我只需要选择“调整”迭代器作为循环中的第一行 // 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
// 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
}
下面Barry提出的一种方法是编写一个范围适配器 在没有
boost
或类似库支持的情况下执行此操作是一种痛苦,但是:
类迭代器
s,并具有begin()
和end()
方法(以及您想要的任何其他方法)到_kv
转换器,该转换器接受一个std::pair cv&
并返回一个struct kv{K cv&key;V cv&value;}
std::map<int, std::string> m;
for (auto kv : as_kv(m)) {
std::cout << kv.key << "->" << kv.value << "\n";
}
这是非常小的,但有效。对于(:)循环,我通常不鼓励这种半自动的伪迭代器;使用真正的迭代器只是一个适度的额外成本,以后不会让人们感到惊讶
(现在有了临时映射支持。还不支持平面C数组)
范围技巧存储一个容器(可能是引用),以便将临时容器复制到(:)的循环期间存储的对象中。非临时容器容器
类型是某种类型的Foo&
,因此它不会产生冗余副本
另一方面,kv\u t
显然只存储引用。迭代器返回临时变量可能会破坏这一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)}; }
对上述->*
憎恶的评论:
因此,->*
被用作Haskell的操作符bind
(与隐式元组解包一起),我们给它一个lambda,它获取映射中包含的数据并返回void。(Haskell式)返回类型成为void(nothing)上的映射,我将其省略为void
这项技术有一个问题:你输了break代码>和继续代码>哪个烂
一个不太受哈奇·哈斯克尔启发的变体会期望lambda返回类似于void | std::experimental::expected
,如果T
是void
则不返回任何内容,如果T
是元组类型则返回映射,如果T
是映射,则加入返回的映射类型。它还可以根据lambda想要什么(SFINAE风格的检测)来解包或不解包包含的元组
但这对于一个如此的答案来说有点过分;这一离题指出,上述编程风格并不是一条完全的死胡同。然而,C++中的非常规性。可以编写类模板:
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)
{ }
};
如果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;
}
最接近它使用的东西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;
}
为了提供另一种几乎可以实现您想要的功能的方法,我在前一段时间编写了这篇文章,以避免代码中出现。首先和。其次:
auto pair2params = [](auto&& f)
{
return [f](auto&& p) {
f(p.first, p.second);
};
};
现在您可以编写如下内容(假设每个
都有一个基于范围的):
intmain()
{
自动值=映射{
{0,“你好”},
{1,“世界!”}
};
for_each(值、pair2参数([])(int键、常量字符串和值){
cout我通常更喜欢亲吻的方式:
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;
模板
typename KeyValuePair::第一种类型和密钥(KeyValuePair和kvp)
{
首先返回kvp;
}
模板
const typename KeyValuePair::first_type&key(const KeyValuePair&kvp)
{
首先返回kvp;
}
模板
无效密钥(const KeyValuePair&&kvp)=删除;
模板
typename KeyValuePair::第二种类型和值(KeyValuePair和kvp)
{
返回kvp.second;
}
模板
const typename KeyValuePair::第二种类型和值(const KeyValuePair&kvp)
{
返回kvp.second;
}
模板
无效值(常量KeyValuePair&&kvp)=删除;
使用如下示例:
for( auto&& [key, value] : container )
for(auto& kvp : my_map) {
std::cout << key(kvp) << " " << value(kvp) << "\n";
}
foreachpair (const Key& key, const Value& value, elems) {
/* ... */
}
#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__)
for(自动和kvp:my_映射){
std::cout在中,我们使用一个名为foreachpair
的宏,它可以这样使用:
for( auto&& [key, value] : container )
for(auto& kvp : my_map) {
std::cout << key(kvp) << " " << value(kvp) << "\n";
}
foreachpair (const Key& key, const Value& value, elems) {
/* ... */
}
#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__)
当然,您可以将键
和值
替换为自动
,以及您想在其中使用的任何限定符。它还支持中断
和继续
我的最新实现如下所示:
for( auto&& [key, value] : container )
for(auto& kvp : my_map) {
std::cout << key(kvp) << " " << value(kvp) << "\n";
}
foreachpair (const Key& key, const Value& value, elems) {
/* ... */
}
#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__)
上面的宏通过包含\uuuu行
编号,为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)
1#定义foreachpair(键、值、元素)\
2个用于(自动和前置要素:要素)\
3 if(false)FOREACH_BREAK:BREAK;/*设置中断路径*/\
4如果(bool FOREACH_CONTINUE=false){}/*var decl*/\
5否则,如果(true)转到FOREACH_BODY;/*跳过循环退出检查*/\
6对于(;)/*确定我们应该中断还是继续。*/\
7如果(!FOREACH\u CONTINUE)转到FOREACH\u BREAK;/*BREAK*/\
8如果为(真)则中断;/*继续*/\
9其他
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)
#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