User-Defined Runtime Function Specifications

Okay, so some time has passed since I wrote something big in C ++, and I'm used to some of the intricacies of more modern languages. This is what scoffed at myself, and I'm sure there is an answer there. Is there a way to call the function specified as a string by the user at runtime? Without resorting to some kind of massive switching / if block?

The situation I'm in is as follows: I have a complete problem with mathematical problems that I solved in C ++ and is listed as "Problem1.cpp / Problem1.h", "Problem2. Cpp / Problem2.h" and etc. Each problem has a function called problemX() (where X is the problem number), which discards the solution. At the beginning of the program, I would like to ask the user: "What problem would you like to solve?" and they will indicate the number. Then I would like to call the corresponding problemX() function without resorting to the massive hard-coded switch statement (or the if statement or an indexed array of function pointers, etc.).

I am sure that this should be possible, but I just can’t remember how to do it. Any ideas?

+4
source share
3 answers

C ++ does not have automatic compilation or runtime of its code in the language. Many library frameworks have a reflection of time in the symbols in the library.

So, solution 1: Insert your problems into your own dynamic libraries, and the main program dynamically loads them and looks for the names of the characters they export.

Solution 2: Replace your raw C-style functions with named objects. So you can:

 class Problem; void RegisterProblem( std::string name, Problem const* problem ); std::map< std::string, Problem const* >& GetProblems(); class Problem { protected: Problem( std::string name ): RegisterProblem( std::move(name), this ) {} virtual void operator() const = 0; virtual ~Problem() {} }; class Problem1: public Problem { public: Problem1():Problem("Problem1") {} virtual void operator() const { /* implementation */ } }; // in .cpp file: Problem1 problem1Instance(); void RegisterProblem( std::string name, Problem const* problem ) { GetProblems()[name] = problem; } std::map< std::string, Problem const* >& GetProblems() { static std::map< std::string, Problem const* > problemMap; return problemMap; } int main() { // parse user input to get this string: std::string testInput = "Problem1"; // run the problem determined by testInput: Problem* prob = GetProblems()[testInput]; Assert(prob); (*prob)(); } 

We have some badly written code error, in which there are self-determining problems (which are registered in the static map) and main (), which fulfills any problem indicated in the line.

I think it would be cleaner:

 // In RegisterProblem.h: // these two have obvious implementations: std::map< std::string, std::function<void()> >& GetProblems(); bool RegisterProblem( std::string s, std::function<void()> ); // always returns true // In problem1.cpp: void Problem1(); // implement this! bool bProblem1Registered = RegisterProblem( "Problem1", Problem1 ); // In problem2.cpp: void Problem2(); // implement this! bool bProblem2Registered = RegisterProblem( "Problem2", Problem2 ); // etc // in main.cpp: int main(int argc, char** argv) { if (argc == 0) return -1; // and maybe print help auto it = GetProblems().find( argv[1] ); if (it == GetProblems().end()) return -1; // and maybe print help it->second(); // call the problem } 

where we eliminate the unnecessary class hierarchy and just maintain the map between the lines and void() functions. The contents of this map apply to every place where functions are written, so there is no central list or if statement.

I would not send anything with such rude code as above, but I hope you understand this idea.

+1
source

unordered_map strings for function pointers.

Insert user input to make sure it's all lowercase (or upper, IF YOU LIKE TO WATCH), and then just find the function. If it exists, call it, otherwise an error.

+5
source

You should use std::map<std::string,_function_pointer_defined_by_you> to store function names as keys, and function pointers as values. You can also use std::unordered_map<std::string,_function_pointer_defined_by_you> , something like std::hash_map . If you can use C ++ 11, you will find std::unordered_map in the <unordered_map> header file, and if you cannot on <tr1/unordered_map> . The map documentation and unordered_map can be found at:

0
source

Source: https://habr.com/ru/post/1443733/


All Articles