假设有人为每个人分别以下列方式制定了单独的职能:
void John_age(void);
void Tom_age(void);
void Kate_age(void);
void Cathy_age(void);
....................
确定他们的年龄。
现在我想通过仅使用人名来调用这些函数,例如:
void age(char* NAME){...}
为该人“NAME”调用特定功能。
void NAME_age(void);
有没有简单的方法在C ++或C中做到这一点?我将衷心感谢您的帮助。感谢。
我用于微控制器的IDE为每个引脚void X_functionName(void);
生成X
格式的可执行函数。所以我正在寻找一种更通用的方法来使用void customName(const char* X)
等函数轻松调用它们。
答案 0 :(得分:6)
这很简单。为年龄函数制作名称地图 typedef使函数指针更容易,静态局部映射使它只被初始化一次,然后" cache"结果。无序地图非常适合这类事情。
C ++ 11:
void age(const std::string& NAME){
static const std::unordered_map<std::string, void(*)()> age_lut = {
{"John",John_age},
{"Tom",Tom_age},
{"Kate",Kate_age},
{"Cathy",Cathy_age},
};
return age_lut.at(Name); //throws std::out_of_range if it doesn't exist
}
C :(这里我使用线性地图而不是像C ++这样的哈希,因为我懒惰)
typedef void(*)() get_age_func_type;
typedef struct {
const char* name;
get_age_func_type func;
} age_lut_type;
age_lut_type age_lookup_table[] = {
{"John",John_age},
{"Tom",Tom_age},
{"Kate",Kate_age},
{"Cathy",Cathy_age},
};
const unsigned age_lookup_table_size =
sizeof(age_lookup_table)/sizeof(age_lut_type);
bool age(char* NAME){
bool found = false;
//if you have a large number of functions,
//sort them in the initialization function, and
//use a binary search here instead of linear.
for(int i=0; i<age_lookup_table_size ; ++i) {
if (stricmp(age_lookup_table[i], NAME)==0) {
age_lookup_table[i].func();
found = true;
break;
}
}
return found;
}
所有这些代码都不在我的脑海中,可能不会按原样进行编译。
实际上,我高度建议不要每个人都有一个功能,而是使用数据。如果绝对需要,请使用枚举而不是字符串来识别它们。
答案 1 :(得分:3)
在C ++中,您创建了一个std::map
函数指针:
typedef void (*Age_Function_Pointer)(void); // Establish synonym for function syntax.
typedef std::map<std::string, Age_Function_Pointer> Lookup_Table;
unsigned int age(char const * name)
{
static bool table_is_initialized = false;
Lookup_Table name_func_map;
if (!table_is_initialized)
{
name_func_map["Cathy"] = Cathy_age;
name_func_map["Kate"] = Kate_age;
name_func_map["Tom"] = Tom_age;
name_func_map["John"] = John_age;
}
std::string name_key = name;
Lookup_Table::const_iterator iterator = name_func_map.find(name_key);
unsigned int persons_age = 0U;
if (iterator != name_func_map.end())
{
persons_age = (*(iterator.second))();
}
return persons_age;
}
类似地,在C中,您可以创建函数指针的查找表:
struct Table_Entry_t
{
char const * name;
Age_Function_Pointer p_func;
};
struct Table_Entry_t Age_Lookup_Table[] =
{
{ "Cathy", Cathy_age},
{ "Kate", Kate_age},
{ "Tom", Tom_age},
{ "John", John_age},
};
const unsigned int NUMBER_OF_ENTRIES =
sizeof(Age_Lookup_Table) / sizeof(Age_Lookup_Table[0]);
unsigned int age(char const * person_name)
{
unsigned int person_age = 0;
unsigned int i = 0;
for (i = 0; i < NUMBER_OF_ENTRIES; ++i)
{
if (strcmp(person_name, Age_Lookup_Table[i]) == 0)
{
person_age = (Age_Lookup_Table[i].p_func)();
break;
}
}
return person_age;
}
答案 2 :(得分:3)
最简单但不可扩展的解决方案是这样的(在c ++中):
void age(std::string name) {
if( name == "John" ) {
John_age();
}
else if( name == "Tom" ) {
Tom_age();
}
else if( name == "Kate" ) {
Kate_age();
}
// and so on
}
简单,可扩展但混乱的解决方案是使用宏:
#define AGE(name) name##_age()
并且不带引号致电:
AGE(John);
答案 3 :(得分:2)
在C ++或C
中有没有简单的方法
在C ++中,不,由于名称错误(除非你对所有可能的函数进行std::unordered_map<void (*)(), std::string>
)。但是在C中,你可以这样做:
void *hndl = dlopen(NULL, RTLD_NOW); // or dlopen(RTLD_DEFAULT, RTLD_NOW)
void (*fptr)(void) = dlsym(hndl, "func_name");
fptr();
答案 4 :(得分:2)
现在我知道你在做什么,我认真地建议你不要那样做。但是,如果你真的想要,多态性可能是一种更有趣的C ++方式,尽管有效性可疑。使用perl / python脚本生成一个模糊的标题:
struct pin_type {
virtual ~pin_type () {}
virtual void name()=0;
virtual void age()=0;
};
struct John_type : public pin_type {
void name() {John_name();}
void age() {John_age();}
};
John_type& John() {static John_type John_; return John_;}
struct Tom_type : public pin_type {
void name() {Tom_name();}
void age() {Tom_age();}
}
Tom_type & Tom() {static Tom_type Tom_; return Tom_;}
... thousands you say?
然后是你的正常代码:
pin* get_pin_by_name(const char* name) {
//look up table of some sort, described by other answers
}
int main() {
pin_type * pin = John(); //instant, and probably allows inlining next calls
pin->age(); //same speed and size as function pointer
pin->name(); //but we avoid multiple lookups
pin = get_pin_by_name("Tom"); //runtime names can be ok too
pin->name(); //calls Tom_name();
}
答案 5 :(得分:0)
您正在描述动态编程语言中常见的功能,而C和C ++则不然。
根据H2CO3和Thomas Matthews的建议使用std::unordered_map<void (*)(), std::string>
在C ++中是一个好主意。
以最小的开销,您可以使用if-else结构。该解决方案应该在C中使用。
void age(char* NAME){
void (*fp)(void);
if (strcmp(NAME, "John") == 0) { fp = John_age; }
else if (strcmp(NAME, "Tom") == 0) { fp = Tom_age; }
/* ... additional cases ... */
else { /* handle bad input */ }
fp(); /* calls the appropriate age function */
}
答案 6 :(得分:0)
还没有人利用constexpr
机制。在这里:
inline unsigned hash(char const* p)
{
int h(0);
for (; *p; ++p)
{
h = 31 * h + static_cast<unsigned char>(*p);
}
return h;
}
constexpr unsigned constHash(char const* in, uint const h)
{
return *in ? constHash(in + 1, 31 * h + static_cast<unsigned char>(*in)) : h;
}
constexpr unsigned constHash(char const* in)
{
return constHash(in, 0);
}
void process(char const* const name)
{
switch (hash(name))
{
case constHash("John"):
//...
break;
case constHash("Tom"):
//...
break;
//...
default:;
}
}