我可以在实际的函数调用中将静态映射定义为函数参数吗?
Can I define a static map as a function argument in the actual function call?
UPDATE:我刚刚对各种解决方案的核心转换逻辑进行了一些基准测试。以下是单个迭代的CPU时间(以纳秒为单位),在Wandbox上进行500万次迭代的平均值:
8 - switch语句
3800 -动态地图
您可以看到,每次创建一个新的映射(动态映射)是相对耗时的。创建一次映射(静态映射),然后只引用它,几乎比快22倍。但是,巧合的是,原来基于交换机的解决方案比静态映射快22倍 !
嗯…我从未考虑过动态映射是可行的解决方案,但对静态映射抱有希望。它比好的老式switch
语句慢了很多,但是8纳秒和176纳秒真的重要吗?
更新结束
核心问题我试图解决是从一个"命名空间"转换到另一个(在一般意义上,不是c++ namespace
关键字)。这在编程中很常见,通常在c++中使用switch
语句来解决,如:
#include <iostream>
enum MUSIC { ROCK, RAP, EDM, COUNTRY };
enum COLOR { RED, BLUE, ORANGE, WHITE };
COLOR convert(MUSIC music)
{
COLOR color = WHITE;
switch (music) {
case RAP: color = RED; break;
case EDM: color = BLUE; break;
case ROCK: color = RED; break;
}
return color;
}
int main()
{
COLOR c = convert(COUNTRY);
std::cout << c << std::endl;
}
下面是我的解决方案(模板将隐藏在头文件的某个地方)。convert()
函数适用于对std::map
有效的任何类型,例如,enum
到enum
和long
到std::string
。第一个参数是键或"from"值,第二个参数是不能转换的默认值,返回值是映射值或"to"值。(特别感谢@Yakk对模板参数推导的帮助。)
#include <iostream>
#include <map>
#include "boost/assign.hpp"
template<class T> struct no_deduction { typedef T type; };
template<typename Key, typename T>
T convert(const Key &k, const T &d, const typename no_deduction<std::map<Key, T> >::type &m) {
typename std::map<Key, T>::const_iterator it = m.find(k);
return it == m.end() ? d : it->second;
}
using boost::assign::map_list_of;
enum MUSIC { ROCK, RAP, EDM, COUNTRY };
enum COLOR { RED, BLUE, ORANGE, WHITE };
int main()
{
COLOR c = convert(COUNTRY, WHITE, map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED));
std::cout << c << std::endl;
}
无论如何,请注意上面的map_list_of
每次调用时都会创建相同的列表。我希望它是静态。这是显而易见的解决方案:
static const std::map<MUSIC, COLOR> m = map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED);
COLOR c = convert(COUNTRY, WHITE, m);
但是我试图使它使用起来简单,特别是,作为一个单一的语句。这里有一个宏解决方案,但我也宁愿避免它。
#define CONVERT(f,t,d,m) do{static const std::map<BOOST_TYPEOF(f), BOOST_TYPEOF(d)> m_ =
map_list_of m; t = convert(f, d, m_);}while(0)
COLOR c;
CONVERT(COUNTRY, c, WHITE, (RAP, RED) (EDM, BLUE) (ROCK, RED));
有没有人知道一些c++ 魔法(实际上是c++ 03)可以调用我的convert()
函数
- 带有静态地图的
- 作为单个语句,而
- 不使用宏?
为什么不直接使用静态数组并对其进行索引呢?
enum MUSIC { ROCK = 0, RAP = 1, EDM = 2, COUNTRY = 3 };
enum COLOR { RED, BLUE, ORANGE, WHITE };
static const COLOR music_to_color[] =
{
RED, //maps to 'ROCK = 0'
BLUE, //maps to 'RAP = 1'
ORANGE, //maps to 'EDM = 2'
WHITE //maps to 'COUNTRY = 3'
};
MUSIC music = RAP;
std::cout << music_to_color[music] << std::endl;
在这种情况下,convert
函数的主体只能是return music_to_color[music]
(其中music
将是参数)。这种方法的优点是速度快,并且没有创建类似std::map
的额外运行时开销。缺点是你不能轻易地在运行时修改映射,而且它更像"C"而不是"c++"(如果你需要c++接口:迭代器等,你可以使用std::array
代替静态数组来减轻痛苦)
另一种方法是使用模板专门化,但这需要大量的输入,如果有很多值要映射,则很难维护。
大写名称通常是为宏保留的,所以我重命名了它们。
在某些时候,您必须编写如何将一种枚举类型转换为另一种枚举类型的工作。使用map最简单的方法如下:
Color convert(Music music)
{
static const std::map<Music, Color> converter = { { Rap, Red }, { Edm, Blue }, { Rock, Red } };
return converter.at(music);
}
使用初始化列表,这是c++ 11的特性。如果你不能使用,你可以试试:
Color convert(Music music)
{
static const struct Once
{
Once()
{
converter[Rap] = Red;
converter[Edm] = Blue;
converter[Rock] = Red;
}
std::map<Music, Color> converter;
} once;
std::map<Music, Color>::const_iterator find_it = once.converter.find(music);
assert(find_it != once.converter.end());
return find_it->second;
}
这段代码可能没有使用花哨的宏,但它是安全的、相当高效的(map的一个实例)和可读的(尽管我确实对该结构体做了一些技巧)。有更快的方法,但它们更复杂,可能不是你用例所必需的。
如果枚举值少于12个,我会考虑只使用switch语句。它通常比map快。
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- C++ 映射的键/值的用户自定义名称?
- 定义具有非标准签名的自定义映射比较器
- 在自定义类型图中重用 SWIG 映射
- 自定义哈希表实现-将字符串映射到整数时出现内存错误
- 如何定义从函数指针到字符串的映射
- 使用自定义比较器C++映射,不插入所有元素
- 如何正确使用带有智能指针和自定义类的映射作为键和值
- C++:对象键的多映射自定义比较器
- 自定义映射类中的分段错误
- C++ 自定义映射键/值不按顺序排列
- C++ 对自定义映射迭代器函数的未定义引用
- 如何在定义映射/集合时实例化比较函数(函子)
- C++类型定义映射错误
- 如何定义映射::迭代器的列表和列表::迭代器的映射
- 如何对自定义映射进行迭代
- 在多线程应用程序中读写自定义映射时堆损坏
- 为不使用元组的自定义映射模拟std::map迭代器
- 预编译头定义映射不可用
- 定时矢量与映射与未定义映射查找