我可以在实际函数调用中将静态映射定义为函数参数吗?

时间:2015-07-17 02:02:11

标签: c++ function dictionary static arguments

更新:我刚刚对各种解决方案的核心转换逻辑进行了一些基准测试。以下是单次迭代的纳秒的CPU时间,平均为Wandbox上的500万次迭代:

8 - 切换声明

176 - 静态地图

3800 - 动态地图

如您所见,每次创建新地图(动态映射)都相对耗时。创建一次地图(静态映射)并在此后仅参考它几乎 22倍。但巧合的是,最初的基于交换机的解决方案比静态映射<22>快

嗯......我从未考虑过动态映射是一种可行的解决方案,但希望能够进行静态映射。它比良好的旧switch语句慢得多,但是8纳秒与176纳秒真的重要吗?

更新结束

核心问题我试图解决的是从一个&#34;命名空间&#34;到另一个(在一般意义上,不是C ++ namespace关键字)。这在编程中很常见,通常使用switch语句在C ++中解决,如下所示:

#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有效的任何类型,例如enumenumlongstd::string。第一个参数是键,或者&#34;来自&#34;值,第二个是默认值,如果不能转换,返回值是映射,或者&#34;到,&#34;值。 (特别感谢@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));

有没有人知道可以调用我的convert()函数的某些C ++ magic (实际上是C ++ 03)

  1. 使用静态地图,
  2. 作为单一陈述,
  3. 不使用宏?

2 个答案:

答案 0 :(得分:2)

大写名称通常是为宏保留的,所以我重命名了它们。

在某些时候,你将不得不完成编码一个枚举类型如何转换为另一个的工作。使用地图的最简单方法如下:

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;
}

这段代码可能不会使用花哨的宏,但它安全,合理有效(地图的一个实例)和可读(虽然我确实在那里用那个结构做了一个技巧)。有更快的方法,但它们更复杂,可能不是您的用例所必需的。

如果枚举值少于十几个,我会考虑使用switch语句。它通常比地图更快。

答案 1 :(得分:2)

为什么不只是简单地使用静态数组并将其编入索引?

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 ++ like”更像“C-like”(如果需要C ++接口,可以使用std::array而不是静态数组来缓解这种痛苦:迭代器等。)

另一种做同样事情的方法是使用模板特化,但这是很多打字,如果你有很多要映射的值,就很难维护。