初始化静态 std::map在 C++

发布于 2024-07-05 10:55:10 字数 42 浏览 6 评论 0原文

初始化静态地图的正确方法是什么? 我们需要一个静态函数来初始化它吗?

What is the right way of initializing a static map? Do we need a static function that will initialize it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

嘿哥们儿 2024-07-12 10:55:10

这是使用 2 元素数据构造函数的另一种方法。 不需要任何函数来初始化它。 没有第 3 方代码(Boost),没有静态函数或对象,没有技巧,只有简单的 C++:

#include <map>
#include <string>

typedef std::map<std::string, int> MyMap;

const MyMap::value_type rawData[] = {
   MyMap::value_type("hello", 42),
   MyMap::value_type("world", 88),
};
const int numElems = sizeof rawData / sizeof rawData[0];
MyMap myMap(rawData, rawData + numElems);

自从我写了这个答案以来,C++11 已经出来了。 您现在可以使用新的初始化程序列表功能直接初始化 STL 容器:

const MyMap myMap = { {"hello", 42}, {"world", 88} };

Here is another way that uses the 2-element data constructor. No functions are needed to initialize it. There is no 3rd party code (Boost), no static functions or objects, no tricks, just simple C++:

#include <map>
#include <string>

typedef std::map<std::string, int> MyMap;

const MyMap::value_type rawData[] = {
   MyMap::value_type("hello", 42),
   MyMap::value_type("world", 88),
};
const int numElems = sizeof rawData / sizeof rawData[0];
MyMap myMap(rawData, rawData + numElems);

Since I wrote this answer C++11 is out. You can now directly initialize STL containers using the new initializer list feature:

const MyMap myMap = { {"hello", 42}, {"world", 88} };
谜兔 2024-07-12 10:55:10

例如:

const std::map<LogLevel, const char*> g_log_levels_dsc =
{
    { LogLevel::Disabled, "[---]" },
    { LogLevel::Info,     "[inf]" },
    { LogLevel::Warning,  "[wrn]" },
    { LogLevel::Error,    "[err]" },
    { LogLevel::Debug,    "[dbg]" }
};

如果map是类的数据成员,则可以通过以下方式直接在头文件中初始化它(C++17起):

// Example

template<>
class StringConverter<CacheMode> final
{
public:
    static auto convert(CacheMode mode) -> const std::string&
    {
        // validate...
        return s_modes.at(mode);
    }

private:
    static inline const std::map<CacheMode, std::string> s_modes =
        {
            { CacheMode::All, "All" },
            { CacheMode::Selective, "Selective" },
            { CacheMode::None, "None" }
            // etc
        };
}; 

For example:

const std::map<LogLevel, const char*> g_log_levels_dsc =
{
    { LogLevel::Disabled, "[---]" },
    { LogLevel::Info,     "[inf]" },
    { LogLevel::Warning,  "[wrn]" },
    { LogLevel::Error,    "[err]" },
    { LogLevel::Debug,    "[dbg]" }
};

If map is a data member of a class, you can initialize it directly in header by the following way (since C++17):

// Example

template<>
class StringConverter<CacheMode> final
{
public:
    static auto convert(CacheMode mode) -> const std::string&
    {
        // validate...
        return s_modes.at(mode);
    }

private:
    static inline const std::map<CacheMode, std::string> s_modes =
        {
            { CacheMode::All, "All" },
            { CacheMode::Selective, "Selective" },
            { CacheMode::None, "None" }
            // etc
        };
}; 
独﹏钓一江月 2024-07-12 10:55:10

我会将地图包装在静态对象内,并将地图初始化代码放入该对象的构造函数中,这样您就可以确保在执行初始化代码之前创建地图。

I would wrap the map inside a static object, and put the map initialisation code in the constructor of this object, this way you are sure the map is created before the initialisation code is executed.

宣告ˉ结束 2024-07-12 10:55:10

只是想分享一个纯 C++ 98 的解决方法:

#include <map>

std::map<std::string, std::string> aka;

struct akaInit
{
    akaInit()
    {
        aka[ "George" ] = "John";
        aka[ "Joe" ] = "Al";
        aka[ "Phil" ] = "Sue";
        aka[ "Smitty" ] = "Yando";
    }
} AkaInit;

Just wanted to share a pure C++ 98 work around:

#include <map>

std::map<std::string, std::string> aka;

struct akaInit
{
    akaInit()
    {
        aka[ "George" ] = "John";
        aka[ "Joe" ] = "Al";
        aka[ "Phil" ] = "Sue";
        aka[ "Smitty" ] = "Yando";
    }
} AkaInit;
亣腦蒛氧 2024-07-12 10:55:10

使用 C++11 初始值设定项列表 {{},{},...}。 初始化元素的顺序并不重要。 地图将根据按键为您进行排序。 如果初始化 unordered_map,则原理相同,排序顺序将由哈希函数确定,并且在人眼看来是随机的:

#include <map>
using namespace std;

map<int, char> m = {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

使用 Boost.Assign

#include <map>
#include "boost/assign.hpp"
using namespace std;
using namespace boost::assign;

map<int, char> m = map_list_of (1, 'a') (3, 'b') (5, 'c') (7, 'd');

Using C++11 initializer list {{},{},...}. The order of the initialized elements does not matter. The map will do the ordering by the key for you. If initializing unordered_map, it is the same principle where the sorted order will be determined by the hashing function and will appear to human eye as random:

#include <map>
using namespace std;

map<int, char> m = {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

Using Boost.Assign:

#include <map>
#include "boost/assign.hpp"
using namespace std;
using namespace boost::assign;

map<int, char> m = map_list_of (1, 'a') (3, 'b') (5, 'c') (7, 'd');
幸福不弃 2024-07-12 10:55:10

最好的方法是使用一个函数:

#include <map>

using namespace std;

map<int,int> create_map()
{
  map<int,int> m;
  m[1] = 2;
  m[3] = 4;
  m[5] = 6;
  return m;
}

map<int,int> m = create_map();

Best way is to use a function:

#include <map>

using namespace std;

map<int,int> create_map()
{
  map<int,int> m;
  m[1] = 2;
  m[3] = 4;
  m[5] = 6;
  return m;
}

map<int,int> m = create_map();
宣告ˉ结束 2024-07-12 10:55:10

制作类似boost的东西并不是一个复杂的问题。 这是一个只有三个函数(包括构造函数)的类,用于复制 boost 所做的(几乎)。

template <typename T, typename U>
class create_map
{
private:
    std::map<T, U> m_map;
public:
    create_map(const T& key, const U& val)
    {
        m_map[key] = val;
    }

    create_map<T, U>& operator()(const T& key, const U& val)
    {
        m_map[key] = val;
        return *this;
    }

    operator std::map<T, U>()
    {
        return m_map;
    }
};

用法:

std::map mymap = create_map<int, int >(1,2)(3,4)(5,6);

上面的代码最适合初始化全局变量或需要初始化的类的静态成员,您不知道它何时首先使用,但您想确保其中的值可用。

如果说,您必须将元素插入现有的 std::map...这是为您准备的另一个类。

template <typename MapType>
class map_add_values {
private:
    MapType mMap;
public:
    typedef typename MapType::key_type KeyType;
    typedef typename MapType::mapped_type MappedType;

    map_add_values(const KeyType& key, const MappedType& val)
    {
        mMap[key] = val;
    }

    map_add_values& operator()(const KeyType& key, const MappedType& val) {
        mMap[key] = val;
        return *this;
    }

    void to (MapType& map) {
        map.insert(mMap.begin(), mMap.end());
    }
};

用法:

typedef std::map<int, int> Int2IntMap;
Int2IntMap testMap;
map_add_values<Int2IntMap>(1,2)(3,4)(5,6).to(testMap);

在 GCC 4.7.2 中查看它的运行情况:http://ideone.com/3uYJiH

############### 下面的所有内容都已过时 #################

编辑:下面的 map_add_values 类(这是我建议的原始解决方案)在 GCC 4.5+ 中会失败。 请查看上面的代码,了解如何向现有地图添加值。


template<typename T, typename U>
class map_add_values
{
private:
    std::map<T,U>& m_map;
public:
    map_add_values(std::map<T, U>& _map):m_map(_map){}
    map_add_values& operator()(const T& _key, const U& _val)
    {
        m_map[key] = val;
        return *this;
    }
};

用法:

std::map<int, int> my_map;
// Later somewhere along the code
map_add_values<int,int>(my_map)(1,2)(3,4)(5,6);

注意:以前我使用运算符[]来添加实际值。 正如达勒评论的那样,这是不可能的。

#################### 过时部分结束 #####################< /强>

It's not a complicated issue to make something similar to boost. Here's a class with just three functions, including the constructor, to replicate what boost did (almost).

template <typename T, typename U>
class create_map
{
private:
    std::map<T, U> m_map;
public:
    create_map(const T& key, const U& val)
    {
        m_map[key] = val;
    }

    create_map<T, U>& operator()(const T& key, const U& val)
    {
        m_map[key] = val;
        return *this;
    }

    operator std::map<T, U>()
    {
        return m_map;
    }
};

Usage:

std::map mymap = create_map<int, int >(1,2)(3,4)(5,6);

The above code works best for initialization of global variables or static members of a class which needs to be initialized and you have no idea when it gets used first but you want to assure that the values are available in it.

If say, you've got to insert elements into an existing std::map... here's another class for you.

template <typename MapType>
class map_add_values {
private:
    MapType mMap;
public:
    typedef typename MapType::key_type KeyType;
    typedef typename MapType::mapped_type MappedType;

    map_add_values(const KeyType& key, const MappedType& val)
    {
        mMap[key] = val;
    }

    map_add_values& operator()(const KeyType& key, const MappedType& val) {
        mMap[key] = val;
        return *this;
    }

    void to (MapType& map) {
        map.insert(mMap.begin(), mMap.end());
    }
};

Usage:

typedef std::map<int, int> Int2IntMap;
Int2IntMap testMap;
map_add_values<Int2IntMap>(1,2)(3,4)(5,6).to(testMap);

See it in action with GCC 4.7.2 here: http://ideone.com/3uYJiH

############### EVERYTHING BELOW THIS IS OBSOLETE #################

EDIT: The map_add_values class below, which was the original solution I had suggested, would fail when it comes to GCC 4.5+. Please look at the code above for how to add values to existing map.


template<typename T, typename U>
class map_add_values
{
private:
    std::map<T,U>& m_map;
public:
    map_add_values(std::map<T, U>& _map):m_map(_map){}
    map_add_values& operator()(const T& _key, const U& _val)
    {
        m_map[key] = val;
        return *this;
    }
};

Usage:

std::map<int, int> my_map;
// Later somewhere along the code
map_add_values<int,int>(my_map)(1,2)(3,4)(5,6);

NOTE: Previously I used a operator [] for adding the actual values. This is not possible as commented by dalle.

##################### END OF OBSOLETE SECTION #####################

记忆之渊 2024-07-12 10:55:10

你在这里有一些非常好的答案,但对我来说,这看起来像是“当你所知道的只是一把锤子时”的情况......

关于为什么没有标准方法来初始化静态地图的最简单的答案,没有充分的理由使用静态映射...

映射是一种为快速查找一组未知元素而设计的结构。 如果您事先知道元素,只需使用 C 数组即可。 以排序的方式输入值,或者对它们运行排序(如果您无法执行此操作)。 然后,您可以通过使用 stl::functions 循环条目 lower_bound/upper_bound 来获得 log(n) 性能。 当我之前对此进行测试时,它们的执行速度通常比地图快至少 4 倍。

优点有很多...
- 更快的性能(*4,我对许多 CPU 类型进行了测量,它总是在 4 左右)
- 更简单的调试。 使用线性布局更容易看到发生了什么。
- 复制操作的简单实现(如果有必要的话)。
- 它在运行时不分配内存,因此永远不会抛出异常。
- 它是一个标准接口,因此很容易在 DLL 或语言等之间共享。

我可以继续,但如果您想要更多,为什么不看看 Stroustrup 关于该主题的许多博客。

You have some very good answers here, but I'm to me, it looks like a case of "when all you know is a hammer"...

The simplest answer of to why there is no standard way to initialise a static map, is there is no good reason to ever use a static map...

A map is a structure designed for fast lookup, of an unknown set of elements. If you know the elements before hand, simply use a C-array. Enter the values in a sorted manner, or run sort on them, if you can't do this. You can then get log(n) performance by using the stl::functions to loop-up entries, lower_bound/upper_bound. When I have tested this previously they normally perform at least 4 times faster than a map.

The advantages are many fold...
- faster performance (*4, I've measured on many CPU's types, it's always around 4)
- simpler debugging. It's just easier to see what's going on with a linear layout.
- Trivial implementations of copy operations, should that become necessary.
- It allocates no memory at run time, so will never throw an exception.
- It's a standard interface, and so is very easy to share across, DLL's, or languages, etc.

I could go on, but if you want more, why not look at Stroustrup's many blogs on the subject.

酒绊 2024-07-12 10:55:10

除了使用的最佳答案之外,

const std::map<int, int> m = {{1,1},{4,2},{9,3},{16,4},{32,9}}

还有一种直接调用 lambda 的可能性,这在某些情况下很有用:

const std::map<int, int> m = []()->auto {
  std::map<int, int> m;
  m[1]=1;
  m[4]=2;
  m[9]=3;
  m[16]=4;
  m[32]=9;
  return m;
}();

显然,当使用文字值从头开始编写时,简单的初始值设定项列表更好,但它确实开辟了其他可能性:(

const std::map<int, int> m = []()->auto {
  std::map<int, int> m;
  for(int i=1;i<5;++i) m[i*i]=i;
  m[32]=9;
  return m;
}();

显然,如果您想重用它,它应该是一个普通函数;并且这确实需要最新的 C++。)

In addition to the good top answer of using

const std::map<int, int> m = {{1,1},{4,2},{9,3},{16,4},{32,9}}

there's an additional possibility by directly calling a lambda that can be useful in a few cases:

const std::map<int, int> m = []()->auto {
  std::map<int, int> m;
  m[1]=1;
  m[4]=2;
  m[9]=3;
  m[16]=4;
  m[32]=9;
  return m;
}();

Clearly a simple initializer list is better when writing this from scratch with literal values, but it does open up additional possibilities:

const std::map<int, int> m = []()->auto {
  std::map<int, int> m;
  for(int i=1;i<5;++i) m[i*i]=i;
  m[32]=9;
  return m;
}();

(Obviously it should be a normal function if you want to re-use it; and this does require recent C++.)

舟遥客 2024-07-12 10:55:10

如果您坚持使用 C++98 并且不想使用 boost,这里有我在需要初始化静态映射时使用的解决方案:

typedef std::pair< int, char > elemPair_t;
elemPair_t elemPairs[] = 
{
    elemPair_t( 1, 'a'), 
    elemPair_t( 3, 'b' ), 
    elemPair_t( 5, 'c' ), 
    elemPair_t( 7, 'd' )
};

const std::map< int, char > myMap( &elemPairs[ 0 ], &elemPairs[ sizeof( elemPairs ) / sizeof( elemPairs[ 0 ] ) ] );

If you are stuck with C++98 and don't want to use boost, here there is the solution I use when I need to initialize a static map:

typedef std::pair< int, char > elemPair_t;
elemPair_t elemPairs[] = 
{
    elemPair_t( 1, 'a'), 
    elemPair_t( 3, 'b' ), 
    elemPair_t( 5, 'c' ), 
    elemPair_t( 7, 'd' )
};

const std::map< int, char > myMap( &elemPairs[ 0 ], &elemPairs[ sizeof( elemPairs ) / sizeof( elemPairs[ 0 ] ) ] );
花开柳相依 2024-07-12 10:55:10

这与 PierreBdR 类似,但无需复制地图。

#include <map>

using namespace std;

bool create_map(map<int,int> &m)
{
  m[1] = 2;
  m[3] = 4;
  m[5] = 6;
  return true;
}

static map<int,int> m;
static bool _dummy = create_map (m);

This is similar to PierreBdR, without copying the map.

#include <map>

using namespace std;

bool create_map(map<int,int> &m)
{
  m[1] = 2;
  m[3] = 4;
  m[5] = 6;
  return true;
}

static map<int,int> m;
static bool _dummy = create_map (m);
╭⌒浅淡时光〆 2024-07-12 10:55:10

你可以试试:

std::map <int, int> mymap = 
{
        std::pair <int, int> (1, 1),
        std::pair <int, int> (2, 2),
        std::pair <int, int> (2, 2)
};

You can try:

std::map <int, int> mymap = 
{
        std::pair <int, int> (1, 1),
        std::pair <int, int> (2, 2),
        std::pair <int, int> (2, 2)
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文