C++ c+中的数据控制程序+;

C++ c+中的数据控制程序+;,c++,arrays,list,dictionary,C++,Arrays,List,Dictionary,我不知道如何命名这个问题,因为问题本身正在寻找一个我不知道其名称的结构 问题是我处理的程序的控制流很大程度上依赖于数据 例如,我创建了一个MIPS模拟器,它实现了一个50多条指令的列表,每条指令都是自己实现的,所有指令都由一个巨大的开关盒控制 switch (function){ //Function is an int, each function (eg SLL) is case 0: //associated with one if (sta

我不知道如何命名这个问题,因为问题本身正在寻找一个我不知道其名称的结构

问题是我处理的程序的控制流很大程度上依赖于数据

例如,我创建了一个MIPS模拟器,它实现了一个50多条指令的列表,每条指令都是自己实现的,所有指令都由一个巨大的开关盒控制

switch (function){ //Function is an int, each function (eg SLL) is 
        case 0:    //associated with one
            if (state->debug_level > 0){
                fprintf(state->debug_out, "SLL\n");
            }
            step_err = SLL(state, rs, rt, rd, sa);
            break;
        case 2:
            if (state->debug_level > 0){
                fprintf(state->debug_out, "SRL\n");
            }
            step_err = SRL(state, rs, rt, rd, sa);
            break;
        case 3:
            if (state->debug_level > 0){
                fprintf(state->debug_out, "SRA\n");
            }
//
有人告诉我,这可以用函数指针实现,但要实现这一点,我要寻找的是一种将任何类型的数据关联起来的方法,比如字符串与其他数据,比如整数。我知道地图,但不想推回每一对。我正在寻找某种类似数组的语法,我认为如果以前见过这种语法,它可能类似于以下内容:

¿type? function_codes[]{
     0, "SLL";
     2, "SRL";
     3, "SRA";
     ...
 }
我不是在寻找这个问题的解决方案,而是寻找一种通用的方法来引入数据之间的快速关系,并使用它来修改控制流

在回答后编辑
我实际上在寻找但我不知道的确实是映射,但特别是它的初始化语法类似于数组(请参阅公认的答案)。这与函数指针一起使用完成了所需的工作。

如果只支持少量索引,从0到50,那么如果将函数指针放在数组而不是映射中,将获得最佳性能

语法也很简短:

#include <iostream>
#include <functional>

static void f0() {
    std::cout << "f0\n";
}

static void f1() {
    std::cout << "f1\n";
}

void main()
{
    std::function<void()> f[2] = { f0, f1 };

    f[0](); // prints "f0"
    f[1](); // prints "f1"
}
#包括
#包括
静态void f0(){

std::cout对于简化,您可以使用关联容器。如果顺序很重要,则使用
std::map
,或者在另一种情况下使用
std::unordered\u map

您可以使用与所需语法类似的语法

std::map<size_t, std::string> codes_map = decltype(codes_map) {
    { 0, "val1" },
    { 1, "val2" }
};
std::map code\u map=decltype(code\u map){
{0,“val1”},
{1,“val2”}
};

您似乎有两个问题:流量控制问题(调度)和地图问题(实施说明)。我知道程序流是非静态的,在编译时是不可知的……但映射也是静态的吗?对于静态映射,我从使用类似于特征的方法创建编译时映射中获得了很多好处。下面是一个映射文件后缀到Objective-C枚举常量的快速示例:

namespace objc {

    namespace image {

        template <std::size_t N> inline
        constexpr std::size_t static_strlen(char const (&)[N]) { return N; }

        template <NSBitmapImageFileType t>
        struct suffix_t;

        #define DEFINE_SUFFIX(endstring, nstype)                                        \
        template <>                                                                     \
        struct suffix_t<nstype> {                                                       \
            static constexpr std::size_t N = static_strlen(endstring);                  \
            static constexpr char const str[N] = endstring;                             \
            static constexpr NSBitmapImageFileType type = nstype;                       \
        };

        DEFINE_SUFFIX("tiff", NSTIFFFileType);
        DEFINE_SUFFIX("bmp",  NSBMPFileType);
        DEFINE_SUFFIX("gif",  NSGIFFileType);
        DEFINE_SUFFIX("jpg",  NSJPEGFileType);
        DEFINE_SUFFIX("png",  NSPNGFileType);
        DEFINE_SUFFIX("jp2",  NSJPEG2000FileType);

        template <NSBitmapImageFileType nstype>
        char const* suffix_value = suffix_t<nstype>::str;

    }
}
namespace-objc{
名称空间映像{
模板内联
constexpr std::size_t static_strlen(char const(&)[N]){return N;}
模板
结构后缀;
#定义后缀(结束字符串,nstype)\
模板\
结构后缀_t{\
static constexpr std::size\u t N=static\u strlen(endstring)\
static constepr char const str[N]=endstring\
静态constexpr NSBitmapImageFileType=nstype\
};
定义_后缀(“tiff”,NSTIFFILETYPE);
定义_后缀(“bmp”,NSBMPFileType);
定义_后缀(“gif”,NSGIFFileType);
定义_后缀(“jpg”,NSJPEGFileType);
定义_后缀(“png”,NSPNGFileType);
定义_后缀(“jp2”,NSJPEG2000FileType);
模板
字符常量*后缀值=后缀t::str;
}
}
…看看它是如何工作的?很好的一点是使用它没有运行时开销,如果你的地图是静态的,你可以使用类似的东西


对于动态流控制和调度,函数指针起作用;如果您使用多态类和
虚拟
函数,就会自动发生这种情况,但似乎您已经有了一个体系结构,可能无法用如此高度现代主义的体系结构概念进行重新设计我喜欢这个领域90%的问题。也许你可以解释一下(我会修改我的答案)!

正如您所猜测的,函数指针实际上是一种很好的方法。由于您指定不想使用映射,这就是如何使用函数指针数组实现基于整数的函数分派。请注意,因为我不知道MIPS函数(SLL、SRL等)的类型签名我使用了虚拟占位符类型名称

typedef ret_t (*mips_func)(arg1_t, arg2_t, arg3_t, arg4_t, arg5_t);

mips_func function_codes[] = {
    &SLL,
    &SRL,
    &SRA,
    ...
};

//...Later, in the part of your code that used to contain the big switch statement
step_err = (*function_codes[function])(state, rs, rt, rd, sa);
语法
&SLL
获取指向函数SLL的指针,我假设它已经在范围内,因为您可以直接从switch语句调用它

请注意,这假设函数的数字代码是从0到[max code value]的连续整数序列。如果某些数字代码未使用,则需要在数组中保留显式间隙(通过在一个或多个条目中放置空指针)或者使用<代码> STD::MAP< /Cord>,以便可以使用任意非连续整数值作为函数的键。幸运的是,使用一个MAP仍然不需要<代码> PursPubSub//Cuthing每个元素,因为C++现在有初始化列表。
typedef ret_t (*mips_func)(arg1_t, arg2_t, arg3_t, arg4_t, arg5_t);

std::map<int, mips_func> function_codes = {
    {0, &SLL},
    {2, &SRL},
    {4, &SRA},
    ...
};

//Using the Map looks exactly the same, due to its overloaded operator[]
step_err = (*function_codes[function])(state, rs, rt, rd, sa);
typedef ret_t(*mips_func)(arg1_t、arg2_t、arg3_t、arg4_t、arg5_t);
标准::映射函数\u代码={
{0,&SLL},
{2,&SRL},
{4,&SRA},
...
};
//由于其重载运算符[],使用映射看起来完全相同
步骤错误=(*函数代码[函数])(状态、rs、rt、rd、sa);

您可以将数据分组为静态成员,并跨结构使用相同的名称,然后使用模板以常规方式访问它们:

struct A { auto call() const { return "((1))"; };  static const char * name; };
struct B { auto call() const { return "{{2}}"; };  static const char * name; };
struct C { auto call() const { return "<<3>>"; };  static const char * name; };
// n.b. these `T...` have: `sizeof(T) == ... == sizeof(empty_struct)`

const char * A::name = "A";
const char * B::name = "B";
const char * C::name = "C";
给出了一些定义

#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdexcept>
#include <map>

using namespace std;

struct state{
    int debug_level = 1;
    const char* debug_out = "%s";
} s;

// some functions to call
void SLL(state& s, int, int, int, int){
    cout << "SLL";
}
void SLR(state& s, int, int, int, int){
    cout << "SLR";
}
void SLT(state& s, int, int, int, int){
    cout << "SLT";
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
结构状态{
int debug_level=1;
const char*debug_out=“%s”;
}s;
//一些要调用的函数
无效SLL(状态与s,整数,整数,整数,整数){
cout second(前进(参数)…);
}
因此,您可以设置一个数组并使用它:-

// array sorted in alphabetical order for binary search to work
pair<string, decltype(SLL)*> name2fn[] = {
        {"SLL", SLL}, 
        {"SLR", SLR},
        {"SLT", SLT}
    };
void callFn(string name, state& s, int a, int b, int c, int d){
    try{
        callFn(name2fn, name, s, a, b, c, d);
    }
    catch(exception& e){
        cout << e.what();
    }
}

// call it  
callFn("SLL", s, 1, 2, 3, 4);
//按字母顺序排序的数组,以便进行二进制搜索
对名称2Fn[]={
{“SLL”,SLL},
{“SLR”,SLR},
{“SLT”,SLT}
};
void callFn(字符串名称、状态和s、int a、,
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdexcept>
#include <map>

using namespace std;

struct state{
    int debug_level = 1;
    const char* debug_out = "%s";
} s;

// some functions to call
void SLL(state& s, int, int, int, int){
    cout << "SLL";
}
void SLR(state& s, int, int, int, int){
    cout << "SLR";
}
void SLT(state& s, int, int, int, int){
    cout << "SLT";
}
auto mappedname2fn = map<string, delctype(SLL)*>{
    {"SLL", SLL}, 
    {"SLR", SLR}
};

// call a map function
mappedname2fn["SLR"](s, 1, 2, 3, 4);
template<typename P, int N, typename ...T> 
auto callFn(P(&a)[N], string val, T&&... params){
    auto it = lower_bound(a, a+N, make_pair(val, nullptr),
        [](auto& p1, auto& p2){return p1.first < p2.first;});
    if(it==(a+N) || val<it->first) throw logic_error("not found");
    return it->second(forward<T>(params)...);
}
// array sorted in alphabetical order for binary search to work
pair<string, decltype(SLL)*> name2fn[] = {
        {"SLL", SLL}, 
        {"SLR", SLR},
        {"SLT", SLT}
    };
void callFn(string name, state& s, int a, int b, int c, int d){
    try{
        callFn(name2fn, name, s, a, b, c, d);
    }
    catch(exception& e){
        cout << e.what();
    }
}

// call it  
callFn("SLL", s, 1, 2, 3, 4);