惯用的 C++ 用于从 const 映射中读取
对于 std::map
BOOST_CHECK_EQUAL(variables["a"], "b");
唯一的问题是,在这种情况下variables
是const
,所以operator[]
不起作用 :(
现在,有几种解决方法;使用 variables.count("a") 舍弃
或者甚至创建一个包装它的函数,在我看来,这些都不像 const
?variables.find("a")- >第二:std::string()operator[]
那样好。有一个标准的方法可以做到这一点(漂亮地)吗?
编辑: 只是为了说明你们都不想给出的答案:不,在 C++ 中没有方便、漂亮、标准的方法来做到这一点。我将必须实现支持功能。
For an std::map<std::string, std::string> variables
, I'd like to do this:
BOOST_CHECK_EQUAL(variables["a"], "b");
The only problem is, in this context variables
is const
, so operator[]
won't work :(
Now, there are several workarounds to this; casting away the const
, using variables.count("a") ? variables.find("a")->second : std::string()
or even making a function wrapping that. None of these seem to me to be as nice as operator[]
. What should I do? Is there a standard way of doing this (beautifully)?
Edit: Just to state the answer that none of you want to give: No, there is no convenient, beautiful, standard way of doing this in C++. I will have to implement a support function.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
根据评论改进实施:
Improved implementation based on comments:
抛弃 const 是错误的,因为 map<> 上的operator[] 如果默认构造的字符串不存在,则将创建该条目。 如果映射实际上位于不可变存储中,那么它将失败。 这一定是这样,因为operator[]返回一个非常量引用以允许赋值。 (例如,m[1] = 2)
一个快速的免费函数来实现比较:
我会考虑语法糖,如果我想到什么就更新。
...
直接的语法糖涉及一个自由函数,它执行map<>::find()并返回一个包装map<>::const_iterator的特殊类,然后重载了operator==()和operator! =() 允许与映射类型进行比较。 所以你可以这样做:
我不相信这比:
它肯定要复杂得多,而且发生的事情不太明显。
包装迭代器的对象的目的是停止使用默认构造的数据对象。 如果您不在乎,则只需使用“获取”答案即可。
为了回应关于 get 优于比较的评论,希望找到一些未来的用途,我有以下评论:
说出你的意思:调用一个名为“check_equal”的函数可以清楚地表明你正在做一个不创建对象的相等比较。
我建议仅在您有需要时才实现功能。 在此之前做某事通常是一个错误。
根据具体情况,默认构造函数可能会产生副作用。 如果要进行比较,为什么要做额外的事情?
SQL 参数:NULL 不等于空字符串。 容器中缺少密钥真的与容器中存在的具有默认构造值的密钥相同吗?
话虽如此,默认构造对象相当于在非常量容器上使用 map<>::operator[]。 也许您当前需要一个返回默认构造对象的 get 函数; 我知道我过去也有过这样的要求。
Casting away const is wrong, because operator[] on map<> will create the entry if it isn't present with a default constructed string. If the map is actually in immutable storage then it will fail. This must be so because operator[] returns a non-const reference to allow assignment. (eg. m[1] = 2)
A quick free function to implement the comparison:
I'll think about syntactic sugar and update if I think of something.
...
The immediate syntactic sugar involved a free function that does a map<>::find() and returns a special class that wraps map<>::const_iterator, and then has overloaded operator==() and operator!=() to allow comparison with the mapped type. So you can do something like:
I'm not convinced that is much better than:
And it is certainly much more complex and what is going on is much less obvious.
The purpose of the object wrapping the iterator is to stop having default constructed data objects. If you don't care, then just use the "get" answer.
In response to the comment about the get being preferred over a comparison in the hope of finding some future use, I have these comments:
Say what you mean: calling a function called "check_equal" makes it clear that you are doing an equality comparison without object creation.
I recommend only implementing functionality once you have a need. Doing something before then is often a mistake.
Depending on the situation, a default constructor might have side-effects. If you are comparing, why do anything extra?
The SQL argument: NULL is not equivalent to an empty string. Is the absence of a key from your container really the same as the key being present in your container with a default constructed value?
Having said all that, a default constructed object is equivalent to using map<>::operator[] on a non-const container. And perhaps you have a current requirement for a get function that returns a default constructed object; I know I have had that requirement in the past.
find
是惯用的形式。 抛弃const
几乎总是一个坏主意。 您必须保证不执行任何写操作。 虽然这对于地图上的读取访问来说是合理的预期,但规范对此没有任何说明。如果您知道该值存在,您当然可以放弃使用
count
进行测试(无论如何,这效率很低,因为这意味着遍历地图两次。即使您不这样做不知道该元素是否存在,我不会使用它,而是使用以下内容:/编辑:正如 Chris 正确指出的那样,
T
类型的对象的默认构造可能 成本高昂,特别是因为即使实际上不需要该对象(因为该条目存在)也会这样做。如果是这种情况,请不要使用def
参数的默认值。在上述情况下。find
is the idiomatic form. Casting awayconst
is almost always a bad idea. You'd have to guarantee that no write operation is performed. While this can be reasonably expected of a read access on a map, the specification doesn't say anything about this.If you know that the value exists you can of course forego the test using
count
(which is quite inefficient, anyway, since it means traversing the map twice. Even if you don't know whether the element exists I wouldn't use this. Use the following instead:/EDIT: As Chris has correctly pointed out, default-construction of objects of type
T
might be expensive, especially since this is done even if this object isn't actually needed (because the entry exists). If this is the case, don't use the default value for thedef
argument in the above case.有趣的是,有两种方法可以在接受的 get 实现中进行模板类型发现(获取值或返回默认构造对象的方法)。 一,您可以执行已接受的操作:
或者您可以使用映射类型并从中获取类型:
这样做的优点是传入的密钥类型不会在类型发现中发挥作用,并且可以是可以隐式转换为密钥的东西。 例如:
An interesting aside, there are two ways do the template type discovery in the get implementation that was accepted (the one that gets the value or returns a default constructed object). One, you can do what was accepted and have:
or you can use the map type and get the types off of that:
The advantage of this is that the type of the key being passed in doesn't play in the type discovery and it can be something that can be implicitly converted to a key. For example:
事实上,operator[] 是 std::map 上的非常量运算符,因为如果映射不存在,它会自动在映射中插入键值对。 (哦副作用!)
正确的方法是使用
map::find
并且,如果返回的迭代器有效 (!= map.end()
),则返回第二
,如您所示。您可以在您正在使用的 std::map 的子类中添加
map::operator[]( const key_type& key ) const
,并将密钥断言为找到,然后返回it->second
。Indeed, operator[] is a non-const one on std::map, since it automatically inserts a key-value pair in the map if it weren't there. (Oooh side-effects!)
The right way is using
map::find
and, if the returned iterator is valid (!= map.end()
), returning thesecond
, as you showed.You could add a
map::operator[]( const key_type& key ) const
in a subclass of the std::map you're using, and assert the key to be found, after which you return theit->second
.这对我来说看起来不太糟糕......我可能不会为此编写函数。
That doesn't look too bad to me... I probably wouldn't write a function for this.
遵循 xtofl 专门化地图容器的想法。 下面的方法效果好吗?
Following up xtofl's idea of specializing the map container. Will the following work well?