C++11:如何获取C++14模板化地图::查找

C++11: how to get C++14 templated map::find

本文关键字:地图 查找 C++14 获取 何获取 C++11      更新时间:2023-10-16

我想知道是否有可能在 C++11 中实现在 C++14(根据 http://en.cppreference.com/w/cpp/container/map/find)中可用的相同模板 map::find 运算符。

template< class K > iterator find( const K& x );

我的具体问题是我的类收到一个 const char*,然后将其转换为 std::string 以将其存储在映射的键中。这对于插入方法没关系(迟早我将不得不创建字符串)。但是,当我在映射中查找项目时,我不想将 const char* 转换为字符串只是为了将其与键进行比较。字符串类已经有一个与常量字符*进行比较的方法。

std::map<std::string, int> map_;
//...
bool find(const char* value)
{
    // a temporary string will be created and passed to find in C++11
    // the const char* will be passed to the key comparer in C++14
    return map_.find(value) != map_.end();
    // in C++11 the above is equivalent to
    std::string temp(value);
    return map_.find(temp) != map_.end();
}

有没有办法避免 C++11 中的临时字符串?

有没有办法避免 C++11 中的临时字符串?

不。您的用例正是他们将此功能添加到 C++14 的原因。按照字面;这是提案中确切的激励示例。

任何替代的标准库解决方案,如使用 lower_bound 或其他算法,通常都会比仅分配内存具有更糟糕的性能问题。

简短的回答:"不。

长答案:不,因为您无权访问std::map内部结构(当然,您可以编写自己的map)。您std::map<std::string, int>的比较器是 bool operator()(const std::string & lhs, const std::string & rhs) const .该比较器使用std::string

一种可能性是使用像bool operator()(const char * lhs, const std::string & rhs) const这样的比较器。我想这就是你的意思。

深入了解Visual Studio 2012中的std::map实现(xutility) - 比较是在如下所示的函数中完成的

template<class _Pr, class _Ty1, class _Ty2> inline
    bool _Debug_lt_pred(_Pr _Pred,
        const _Ty1& _Left, _Ty2& _Right,
        _Dbfile_t _File, _Dbline_t _Line)
    {   // test if _Pred(_Left, _Right) and _Pred is strict weak ordering
    if (!_Pred(_Left, _Right))
        return (false);
    else if (_Pred(_Right, _Left))
        _DEBUG_ERROR2("invalid operator<", _File, _Line);
    return (true);
    }

_Pred是比较函数。您可以看到此功能与_Pred(_Left, _Right)_Pred(_Right, _Left)一起使用。这就是为什么bool operator()(const char * lhs, const std::string & rhs) const无济于事。它不是对称的。

如果你负责容器类型并愿意改变它,并且你不介意将你的键值对视为 const(即,你无意在插入元素后更新值),那么 Boost.MultiIndex 可以与ordered_unique索引一起使用来代替std::map<>

#include <utility>
#include <string>
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
struct transparent_less
{
    using is_transparent = int;
    template<typename T, typename U>
    constexpr
    decltype(std::declval<T&&>() < std::declval<U&&>())
    operator ()(T&& lhs, U&& rhs) const
        noexcept(noexcept(std::declval<T&&>() < std::declval<U&&>()))
    {
        return std::forward<T>(lhs) < std::forward<U>(rhs);
    }
};
namespace bmi = boost::multi_index;
template<typename K, typename V>
using transparent_map = bmi::multi_index_container<
    std::pair<K, V>,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::member<std::pair<K, V>, K, &std::pair<K, V>::first>,
            transparent_less
        >
    >
>;
int main()
{
    transparent_map<std::string, int> map;
    map.emplace("foo", 1);
    map.emplace("bar", 2);
    std::cout << map.find("foo")->second << 'n'; // no std::string constructed
}

在线演示

除了不能改变一个值,并且没有operator[],这应该提供与std::map<>相同的接口。