不确定如何命名这个问题,因为问题本身正在寻找一个我不知道其名称的构造。
问题是我正在处理控制流程主要取决于数据的程序。
例如,我创建了一个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 :(得分:4)
正如您所猜测的,函数指针实际上是一种很好的方法。由于您指定不想使用Map,因此您将使用函数指针数组实现基于整数的函数调度。请注意,由于我不知道MIPS函数(SLL,SRL等)的类型签名,因此我使用了虚拟占位符类型名称。
update student
set isActive = false, Relieved_Date = '2015-01-20'
where Roll_Number in (101, 104, 107, 108);
语法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的指针,我假设它已经在范围内,因为您可以直接从switch语句中调用它。
请注意,这假定函数的数字代码是从0到[最大代码值]的连续整数序列。如果某些数字代码未使用,那么您需要在数组中留下明确的间隙(通过在一个或多个条目中放置NULL指针)或使用&SLL
以便您可以使用任意非连续的整数值功能的关键。幸运的是,使用Map仍然不需要std::map<int, mips_func>
每个元素,因为C ++现在有初始化列表。使用Map的相同代码如下所示:
push_back
答案 1 :(得分:3)
为简化起见,您可以使用关联容器。如果订单很重要,请在另一种情况下使用std::map
或std::unordered_map
。
您可以使用与所需
类似的语法std::map<size_t, std::string> codes_map = decltype(codes_map) {
{ 0, "val1" },
{ 1, "val2" }
};
答案 2 :(得分:1)
您可以将数据分组为跨结构的相同名称的静态成员,然后使用模板一般地访问它们:
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";
boost::variant
(以及即将实现的std::variant
)实现了一个类型安全联合,它提供了一种非常干净有效的方法来将这些结构用作值:
#include <cstdio>
#include <vector>
#include <boost/variant.hpp>
int main()
{
std::vector<boost::variant<A, B, C>> letters{A{}, B{}, C{}, B{}, A{}};
auto visitor = [](auto x) { std::printf("%s(): %s\n", x.name, x.call()); };
for (auto var : letters) { boost::apply_visitor(visitor, var); }
}
答案 3 :(得分:0)
如果您只支持少量索引,从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"
}
或者,如果您更喜欢类而不是函数:
#include "stdafx.h"
#include <iostream>
class myfunc {
public:
virtual void run() abstract;
virtual ~myfunc() {}
};
class f0 : public myfunc {
public:
virtual void run() {
std::cout << "f0\n";
}
};
class f1 : public myfunc {
public:
virtual void run() {
std::cout << "f1\n";
}
};
void main()
{
myfunc* f[2] = { new f0(), new f1() };
f[0]->run(); // prints "f0"
f[1]->run(); // prints "f1"
for (int i = 0; i < sizeof(f) / sizeof(f[0]); ++i)
delete f[i];
}
答案 4 :(得分:0)
看起来你有两个问题:流量控制问题(调度)和地图问题(实施说明)。我得知程序流是非静态的,在编译时是不可知的......但是地图静态也是如此吗?对于静态映射,我使用traits-ish方法创建编译时映射会获得很多好处。这是一个将文件后缀映射到Objective-C枚举常量的快速示例:
f = 4.9; % Focal length is given as 4.9mm
sensor_size = [6.17 4.55]; % Again in mm
cc = sensor_size ./ 2;
% Calculate intrinsic matrix
KK = [f 0 cc(1);0 f cc(2); 0 0 1];
theta = 21.8; % Angle of camera above plane, degrees
Rc = xrotate(theta) % xrotate fcn given below
Tc = [0 0 60]'; % Camera is 60mm above plane along camera z-axis
H = KK * [R(:,1) R(:,2) Tc];
figure;imshow(imtransform(I,maketform('projective',H), 'Size', image_size))
function R = xrotate( theta )
R = [ 1 0 0;
0 cosd(theta) sind(theta);
0 -sind(theta) cosd(theta) ];
end
......看看它是如何运作的?好的部分是使用它没有运行时开销,如果你的地图是静态的,你可以使用类似的东西。
对于动态流控制和调度,函数指针有效;如果您使用多态类和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;
}
}
函数,那就是自动发生的情况,但似乎您已经建立了一个可能不适合用这种高现代主义建筑概念重做的架构。我喜欢c ++ 11 lambdas,因为他们在这个领域解决了我90%的问题。也许你可以详细说明(我会修改我的答案)!
答案 5 :(得分:0)
给出一些定义
#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);