当前位置:  开发笔记 > 编程语言 > 正文

用于从const映射中读取的惯用C++

如何解决《用于从const映射中读取的惯用C++》经验,为你挑选了4个好方法。

对于std::map variables,我想这样做:

BOOST_CHECK_EQUAL(variables["a"], "b");

唯一的问题是,在这种情况下variablesconst,所以operator[]不会工作:(

现在,有几种解决方法; 扔掉const,使用variables.count("a") ? variables.find("a")->second : std::string()甚至制作包裹它的功能.在我看来,这些都不如同operator[].我该怎么办?有没有一种标准的方法(漂亮)?

编辑:只是说出你们没有想要给出的答案:不,在C++中没有方便,美观,标准的方法.我将不得不实现一个支持功能.



1> Chris Jester..:
template 
V get(std::map const& map, K const& key)
{
    std::map::const_iterator iter(map.find(key));
    return iter != map.end() ? iter->second : V();
}

改进了基于评论的实施:

template 
typename T::mapped_type get(T const& map, typename T::key_type const& key)
{
    typename T::const_iterator iter(map.find(key));
    return iter != map.end() ? iter->second : typename T::mapped_type();
}



2> janm..:

抛弃const是错误的,因为map <>上的operator []将创建条目(如果它不存在默认的构造字符串).如果地图实际上在不可变存储中,那么它将失败.这必须是这样的,因为operator []返回一个非const引用以允许赋值.(例如,m [1] = 2)

一个快速免费的功能来实现比较:

template
bool check_equal(const CONT& m, const typename CONT::key_type& k,
                    const typename CONT::mapped_type& v)
{
    CONT::const_iterator i(m.find(k));
    if (i == m.end()) return false;
    return i->second == v;
}

如果我想到的话,我会考虑语法糖和更新.

...

直接的语法糖涉及一个自由函数,它执行map <> :: find()并返回一个包含map <> :: const_iterator的特殊类,然后重载operator ==()和operator!=()以允许与映射类型进行比较.所以你可以这样做:

if (nonmutating_get(m, "key") == "value") { ... }

我不相信这比以下更好:

if (check_equal(m, "key", "value")) { ... }

它肯定要复杂得多,而且发生的事情则不那么明显.

包装迭代器的对象的目的是停止使用默认的构造数据对象.如果您不在乎,那么只需使用"获取"答案即可.

为了回应关于比较优先的评论,希望找到未来的用途,我有以下评论:

说出你的意思:调用一个名为"check_equal"的函数可以清楚地表明你在没有创建对象的情况下进行了相等比较.

我建议只在您需要时才实现功能.在此之前做某事通常是个错误.

根据具体情况,默认构造函数可能有副作用.如果您正在比较,为什么要做额外的事情?

SQL参数:NULL不等于空字符串.容器中是否缺少密钥与使用默认构造值的容器中存在的密钥完全相同?

说了这么多,默认构造对象相当于在非const容器上使用map <> :: operator [].也许你对get函数有一个当前的要求,它返回一个默认的构造对象; 我知道我过去曾有这个要求.



3> Konrad Rudol..:

find是惯用的形式.抛弃const几乎总是一个坏主意.您必须保证不执行写操作.虽然可以合理地预期地图上的读访问,但规范并没有说明这一点.

如果您知道该值存在,您当然可以放弃使用测试count(这是非常低效的,无论如何,因为它意味着遍历地图两次.即使您不知道该元素是否存在,我也不会使用它.以下代替:

T const& item(map const& m, TKey const& key, T const& def = T()) {
    map::const_iterator i = m.find(key);
    return i == m.end() ? def : i->second;
}

/编辑:正如Chris正确指出的那样,类型对象的默认构造T 可能很昂贵,特别是因为即使实际上不需要这个对象(因为条目存在),这样做也是如此.如果是这种情况,请不要def在上述情况下使用参数的默认值.



4> Matt Price..:

有趣的是,在get实现中有两种方式可以接受(获取值或返回默认构造对象的模板类型).一,你可以做什么被接受,并有:

template 
V get1(const std::map& theMap, const K const key)
{
    std::map::const_iterator iter(theMap.find(key));
    return iter != theMap.end() ? iter->second : V();
}

或者您可以使用地图类型并从中获取类型:

template
typename T::mapped_type
get2(const T& theMap, const typename T::key_type& key)
{
    typename T::const_iterator itr = theMap.find(key);
    return itr != theMap.end() ? itr->second : typename T::mapped_type();
}

这样做的好处是传入的密钥类型不会在类型发现中播放,它可以是可以隐式转换为密钥的东西.例如:

std::map data;
get1(data, "hey"); // doesn't compile because the key type is ambiguous
get2(data, "hey"); // just fine, a const char* can be converted to a string

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有