c++函数在宏值上切换语句或数组抽象

C++ function switch statement or array abstract over macro values

本文关键字:语句 数组 抽象 函数 c++      更新时间:2023-10-16

考虑以下代码:

#define VAL_A 0
#define VAL_B 1
#define VAL_C 2
void TestSwitch01(uint32 val)
{
    printf("%u: ", op);
    switch (val)
    {
    case VAL_A: printf("aaan"); break;
    case VAL_B: printf("bbbn"); break;
    case VAL_C: printf("cccn"); break;
    default: printf("dddn");
    }
}
#define VAL_A 10
#define VAL_B 11
#define VAL_C 12
void TestSwitch02(uint32 op)
{
    printf("%u: ", op);
    switch (val)
    {
    case VAL_A: printf("aaan"); break;
    case VAL_B: printf("bbbn"); break;
    case VAL_C: printf("cccn"); break;
    default: printf("dddn");
    }
}

在这个例子中,我有三个VAL_*宏和两个TestSwitch*()函数。然而,假设我有这种模式,但有5000个VAL_*宏和20个TestSwitch*()函数(换句话说- 20个不同版本的VAL_A - 0,10等)。此外,我在单独的文件中有#define…所以foo001.h有(0 12)个VAL 's, foo002.h有(10 11 12)个VAL 's。

我不想复制粘贴函数的20个版本,因为它是同一个函数。所以我真的想写一个抽象于宏之上的函数。

显然,我可以使用变量,但我不想这样做,因为变量将在运行时设置,这会很慢。我想写c++代码,让编译器生成20个版本的TestSwitch*(),每个版本对应于20个不同的5000个VAL*宏集之一。

我想避免写一个宏伪函数,因为你不能进入其中,而且它很难阅读(语法高亮和智能感知也不起作用)。

我考虑使用模板函数,但是有5000个VAL_*宏,这将是相当疯狂的…template void <uint32 VAL_A, uint32 VAL_B ... VAL_4999> TestSwitch(...) .

我还试图通过用函数指针数组替换switch()语句来做到这一点(到printf() 's)…但是,在填充数组时,我仍然有复制粘贴代码的问题。

我觉得c++有工具来做我想做的事情,但我不确定如何…什么好主意吗?

基本上我想生成20个函数TestSwitchXX()的副本-每组5000个VAL_*一个。

也许有一些技巧使用多个文件和#include#if ?

一个合适的c++解决方案是取消#define s并在结构体中使用枚举:

struct Foo {
    enum { VAL_A = 0, VAL_B = 1, VAL_C = 2 };
};
struct Bar {
    enum { VAL_A = 10, VAL_B = 11, VAL_C = 12 };
};
template<typename T>
void TestSwitch(int op)
{
    std::cout << op << ": ";
    switch (op) {
        case T::VAL_A: std::cout << "aaan"; break;
        case T::VAL_B: std::cout << "bbbn"; break;
        case T::VAL_C: std::cout << "cccn"; break;
        default: break;
    }
}

演示:http://ideone.com/u3kTtF

你也可以用enum class代替struct,但是你只能有值,struct选项让你有机会包含其他描述T的东西的值,这些值以后可能会有用。

枚举类Demo: http://ideone.com/DBZuyn

XMacros -他们是趋势…让我看看……对啊,2001 .

在:

行"generate_testswitch.h"

#define IMPLEMENT_TEST_SWITCH(N) void TestSwitch#N(uint32 val) 
{ 
    printf("%u: ", op); 
    switch (val) 
    { 
    case VAL_A: printf("aaan"); break; 
    case VAL_B: printf("bbbn"); break; 
    case VAL_C: printf("cccn"); break; 
    default: printf("dddn"); 
    } 
}
"testswitch1.c"

// you may isolate these in yet another header
#define VAL_A 0
#define VAL_B 1
#define VAL_C 2
#include "generate_testswitch.h"
IMPLEMENT_TEST_SWITCH(01)

我考虑使用模板函数,但是有5000个VAL_*宏,这将是相当疯狂的…template void <uint32 VAL_A, uint32 VAL_B ... VAL_4999> TestSwitch(...) .

对于您将问题标记为c++,我认为可以使用标准的最新版本(或至少c++ 11)。
正因为如此,不,使用模板并不是很疯狂。
您可以使用可变模板做类似的事情:

template<typename T, T... V>
void TestSwitch(uint32_t val) {
    // ...
}

因此你可以这样调用它:

TestSwitch<int, 10, 11, 12>(42);

我不清楚你想对这些值做什么,所以很难说函数体必须如何编写。
作为一个简单的例子,它遵循一个实现,检查val是否包含在V...中:

template<typename T, T... V>
void TestSwitch(uint32_t val) {
    bool found = false;
    int arr[] = { 0, (found = found || (val == V), 0 )... };
    (void)arr;
    std::cout << "found: " << found << std::endl;
}

其他问题可能需要一个空的递归等等。


只要你处理范围,你也可以这样做:

#include <cstddef>
#include <functional>
#include <iostream>
template<std::size_t B, std::size_t... I>
void TestSwitch(uint32_t val, std::index_sequence<I...>) {
    bool found = false;
    int arr[] = { 0, (found = found || (val == (B+I)), 0 )... };
    (void)arr;
    std::cout << "found: " << found << std::endl;
}
template<std::size_t B, std::size_t N>
void TestSwitch(uint32_t val) {
    TestSwitch<B>(val, std::make_index_sequence<N>{});
}
int main() {
    TestSwitch<40, 3>(42);
    TestSwitch<40, 3>(0);
}

在本例中,我们使用基数(即起始值)和范围长度调用TestSwitch,然后我们依靠std::make_index_sequence和另外一个函数来生成范围本身并完成工作。