Vector of fuctions_pointers whit different prototype, can i build one?

心不动则不痛 提交于 2020-08-08 05:38:25

问题


I'm doing a parsser for a class call virtual_machine, I'm trying to build a vectors of function for it, but some of those function on vm takes arguments (different numbers/types of arguments) can i still put those in my vector of fuction since they where only void (*f)();

here's the code


class Virtual_Machine {
    public:
      /***/
        void clear();
        void pop();
        void clear();
        void assert(std::string const &value);
        void push(eOperandType const &e, std::string const &str);
      /***/
}

class Parser {
    public:
       /***/
        void prepare();
        void add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand);

    private:
        Virtual_Machine vm;
        std::vector<std::string> command_no_arg;
        std::vector<void (Virtual_Machine::*)()> func_no_arg;
        /***/

};

void Parser::add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand)
{
    command_no_arg.push_back(comand);
    func_no_arg.push_back(f);

}

void Parser::prepare()
{
    add_func_no_arg(&Virtual_Machine::dump,"dump");
    add_func_no_arg(&Virtual_Machine::pop,"pop");
    add_func_no_arg(&Virtual_Machine::clear,"clear");
}
void Parser::use_exemple()
{
    // dump :
    (vm.*(func_no_arg[0]))();
}

this is ok but now I will to kwon if it's possible to add push() and assert() toi my vector of funtions , what do i need to do ? i was thinking maybe templat but i realy don't see how


回答1:


Daniel Jour's extensive linked answer shows how hiding away the arguments can be achieved with packing and boost::any and is probably a better solution (but I didn't fully understand it). As alternative you can use variadic functions as in the example below.

Please take my code with a grain of salt, I encountered some restrictions and I am not an expert on the topic:

  • you cannot receive reference type arguments through ...
  • const arguments are promoted to non-const ones (in my test const int got promoted to int)
  • I assume variadic functions are a security risk. Please check/ sanitize the input if the function arguments are provided by a user.

Here is the code example (note that I renamed Virtual_Machine::assert to Virtual_Machine::vmassert to use assert from <cassert>):

#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <cstdarg>

class Virtual_Machine
{
    private:
        std::string name;

    public:
        Virtual_Machine(std::string n) : name(n) {}
        void clear(size_t nargs, ...){std::cout << "Clear " << name << std::endl;};
        void dump(size_t nargs, ...){std::cout << "Dump" << std::endl;};
        void vmassert(size_t nargs, ...)
        {
            va_list args;
            va_start(args, nargs);

            assert(nargs == 1);
            const std::string value(va_arg(args, std::string));
            std::cout << "Assert " << value << std:: endl;

            va_end(args);
        }
        void push(size_t nargs, ...)
        {
            va_list args;
            va_start(args, nargs);

            assert(nargs == 2);
            const int e(va_arg(args, int));
            const std::string str(va_arg(args, std::string));
            std::cout << "Push " << e << ", " << str << std:: endl;
            va_end(args);
        }
};

class Parser
{
    private:
        Virtual_Machine vm;
        std::vector<std::string> commands;
        std::vector<void (Virtual_Machine::*)(size_t, ...)> funcs;

    public:
        Parser(std::string vm_name) : vm(vm_name) {}
        void add_func(
                void (Virtual_Machine::* f)(size_t, ...),
                std::string command)
        {
            commands.push_back(command);
            funcs.push_back(f);
        }
        void prepare()
        {
            add_func(&Virtual_Machine::clear, "clear");
            add_func(&Virtual_Machine::dump, "dump");
            add_func(&Virtual_Machine::vmassert, "assert");
            add_func(&Virtual_Machine::push, "push");
        }
        void test()
        {
            (vm.*(funcs[0]))(0);
            (vm.*(funcs[1]))(0);
            (vm.*(funcs[2]))(1, std::string("abc"));
            (vm.*(funcs[3]))(2, 42, std::string("def"));
        }
};

int main()
{
    Parser a("vm_a");

    a.prepare();
    a.test();

    return 0;
}

I changed the signature of all Virtual_Machine member functions to (size_t nargs, ...) in this way you have a uniform type for all functions that you can use to declare Parser::funcs. Each function now has to be called with the number of arguments followed by the actual arguments.



来源:https://stackoverflow.com/questions/62922933/vector-of-fuctions-pointers-whit-different-prototype-can-i-build-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!