【发布时间】:2014-02-06 19:23:29
【问题描述】:
考虑下面的代码
#include <iostream>
enum MyEnum{
A,
B,
END
};
template <int N>
class Trait {};
template<>
class Trait<A> {
public:
static int funct(int i) {return i*3;}
};
template<>
class Trait<B> {
public:
static int funct(int i) {return i*24;}
};
using namespace std;
int main(){
int i = 1;
switch(i){
case A: cout << Trait<A>::funct(i) << endl; break;
case B: cout << Trait<B>::funct(i) << endl; break;
}
}
这将在屏幕上打印 24。
现在假设我在枚举中有更多的值,并且我定义了所有对应的 类 Trait 的模板特化。
为了避免在 switch 语句中编写所有必要的代码,我编写了一个 REPEAT 宏,它几乎可以像我想要的那样工作:
#include <iostream>
#define REPEAT(N, macro) REPEAT_##N(macro)
#define REPEAT_0(macro)
#define REPEAT_1(macro) REPEAT_0(macro) macro(0)
#define REPEAT_2(macro) REPEAT_1(macro) macro(1)
#define REPEAT_3(macro) REPEAT_2(macro) macro(2)
#define REPEAT_4(macro) REPEAT_3(macro) macro(3)
// etc...
// enum and class definitions
int main(){
#define MY_MACRO(N) case N: cout << Trait<N>::funct(i) << endl; break;
switch(i){
REPEAT(2, MY_MACRO)
}
}
这种方法的问题是我无法使用
REPEAT(END, MY_MACRO)
因为预处理器不知道我的枚举。
问题:有没有办法自动生成switch语句?
注意事项:
- 我必须使用它的情况要复杂得多,自动化的东西会非常有帮助。
- 使用 switch 语句对我来说很重要,因为它可以实现速度(速度对我的应用程序至关重要)。
谢谢!
编辑 1
更多说明:
- 重要的是,开关的生成取决于枚举中定义的 END 值。
编辑 2/3
我决定在这里做一个补充以更好地解释我的应用程序以及为什么我更喜欢某些解决方案而不是其他解决方案
- 在我的实际应用程序中,枚举包含近 50 个不同的值,并且将来会扩展(希望由其他人)。枚举包含连续值。
- “Trait”类有多个成员函数(目前为 5 个)。此外,我需要在 5 个不同的文件中使用所有这些。如果我不使用自动生成所需内容的方式,我最终会多次编写基本相同的代码。
- Trait 的成员函数始终以相同的方式使用。
-
目前,在我的开关中,我有一个如下所示的函数调用(in1、in2 和 out 都是通过引用进行双重传递,前两种情况下为 const)。
案例A:特征::funct(in1, in2, out);休息;
我为什么喜欢模板?
假设 Trait 有 2 个函数 funct1 和 funct2。我可以定义
template <int N>
class Trait {
public:
static int funct1(int i){static_assert(N!=N, "You forgot to define funct1");}
static int funct2(int i){static_assert(N!=N, "You forgot to define funct2");}
};
现在,如果缺少函数定义,编译器将返回一个有意义的错误。当其他人进行添加时,这将很有帮助。
使用 Jarod42 建议的基于 C++11 特性的方法,我可以避免维护容易出错的长函数指针数组。
速度测试
到目前为止,我尝试了 3 种解决方案,但 Trait 中只有两个成员函数:
- Jarod42 建议的解决方案
- nndru 和 Ali 建议的简单函数指针数组
- 带有 RETURN 宏的 switch 语句
前两种解决方案似乎是等价的,而基于 switch 的解决方案快 5 倍。我使用带有标志 -O3 的 gcc 版本 4.6.3。
【问题讨论】:
-
嗨。为什么你不在你的枚举成员和分配给它的某种函子之间使用映射。
-
正如我在笔记中所写的,速度对我来说真的很重要。我认为使用地图会使代码变慢。
-
地图是一个快速搜索容器,我认为是个好主意:D
-
我知道map很快,但是switch语句通常编译成跳转表会快很多。
-
好的,你可以针对 map 使用数组:用整数分配枚举成员并将仿函数存储在数组中,其中枚举 id 将是数组单元格 id。
标签: c++ macros enums switch-statement