Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Container for different functions?

I'm trying to implement a container class for different functions where I can hold function pointers and use it to call those functions later. I'll try to discribe my problem more accurate.

As example, I have 2 different test functions:

int func1(int a, int b) { 
    printf("func1 works! %i %i\n", a, b);
    return 0;
}
void func2(double a, double b) {
    printf("func2 works! %.2lf %.2lf\n", a, b);
}

and I also have array of variants, which holds function arguments:

std::vector<boost::variant<int, double>> args = {2.2, 3.3};

I've decided to use my own functor class derived from some base class ( I thought about using virtual methods):

class BaseFunc {
public:
    BaseFunc() {}
    ~BaseFunc() {}
};

template <typename T>
class Func;

template <typename R, typename... Tn>
class Func<R(Tn...)> : public BaseFunc {
    typedef R(*fptr_t)(Tn...);
    fptr_t fptr;
public:
    Func() : fptr(nullptr) {}
    Func(fptr_t f) : fptr(f) {}
    R operator()(Tn... args) {
        return fptr(args...);
    }
    Func& operator=(fptr_t f) {
        fptr = f;
        return *this;
    }
};

Also I've decided to store some information about function and its arguments:

struct TypeInfo {
    int type_id; // for this example: 0 - int, 1 - double

    template <class T>
    void ObtainType() {
        if (std::is_same<void, T>::value)
            type_id = 0;
        else if (std::is_same<int, T>::value)
            type_id = 1;
        else if (std::is_same<double, T>::value)
            type_id = 2;
        else
            type_id = -1;
    }
};

struct FunctionInfo {
public:
    FunctionInfo() {}
    FunctionInfo(BaseFunc *func, const TypeInfo& ret, std::vector<TypeInfo>& args) :
        func_ptr(func), return_info(ret)
    {
        args_info.swap(args);
    }
    ~FunctionInfo() {
        delete func_ptr;
    }

    BaseFunc * func_ptr;
    TypeInfo return_info;
    std::vector<TypeInfo> args_info;
};

So now I can define a container class:

class Container {
private:
    template <size_t n, typename... T>
    void ObtainTypeImpl(size_t i, TypeInfo& t)
    {
        if (i == n)
            t.ObtainType<std::tuple_element<n, std::tuple<T...>>::type>();
        else if (n == sizeof...(T)-1)
            throw std::out_of_range("Tuple element out of range.");
        else
            ObtainTypeImpl<(n < sizeof...(T)-1 ? n + 1 : 0), T...>(i, t);
    }
    template <typename... T>
    void ObtainType(size_t i, TypeInfo& t)
    {
        return ObtainTypeImpl<0, T...>(i, t);
    }
public:
    template <class R, class ...Args>
    void AddFunc(const std::string& str, R(*func)(Args...)) {
        BaseFunc * func_ptr = new Func<R(Args...)>(func);
        size_t arity = sizeof...(Args);
        TypeInfo ret;
        ret.ObtainType<R>();
        std::vector<TypeInfo> args;
        args.resize(arity);
        for (size_t i = 0; i < arity; ++i)
        {
            ObtainType<Args...>(i, args[i]);
        }
        cont_[str] = FunctionInfo(func_ptr, ret, args);
    }
    void CallFunc(const std::string& func_name, 
                  std::vector<boost::variant<int, double>>& args_vec) {
        auto it = cont_.find(func_name);
        if (it != cont_.end())
        {
            // ???????
            // And here I stucked
        }
    }
private:
    std::map<std::string, FunctionInfo> cont_;
};

And then I stucked.

  1. Don't know how to get function type information from my struct :).
  2. Don't know how to convert vector of variants to arguments list.

Maybe my path was wrong? Can you suggest any solution of this problem except script engine like Lua?

like image 245
shtille Avatar asked Dec 15 '14 16:12

shtille


People also ask

What are container and functions?

Definitions. Containers: From Docker's website: “A container image is a lightweight, stand-alone, executable package of a piece of software that includes everything needed to run it: code, runtime, system tools, system libraries, settings.” Functions : Functions are blocks of code, ideally small and single-purpose.

What is an STD container?

An STL container is a collection of objects of the same type (the elements). Container owns the elements. Creation and destruction is controlled by the container.

What are the containers in C?

A container is an object that stores a collection of elements (i.e. other objects). Each of these containers manages the storage space for their elements and provides access to each element through iterators and/or member functions.

What are the various types of STL containers?

Types of STL Container in C++ In C++, there are generally 3 kinds of STL containers: Sequential Containers. Associative Containers. Unordered Associative Containers.


1 Answers

You may do something like:

class BaseFunc {
public:
    virtual ~BaseFunc() = default;

    virtual void Call(std::vector<boost::variant<int, double>>& args_vec) const = 0;
};

template <typename F> class Function;

template <typename R, typename... Args> class Function<R(Args...)> : public BaseFunc
{
public:
    Function(R (*f)(Args...)) : f(f) {}
    void Call(std::vector<boost::variant<int, double>>& args_vec) const override
    {
        Call(args_vec, std::index_sequence_for<Args...>());
    }
private:
    template <std::size_t ... Is>
    void Call(
        std::vector<boost::variant<int, double>>& args_vec,
        std::index_sequence<Is...>) const
    {
        // Add additional check here if you want.
        f(boost::get<Args>(args_vec.at(Is))...);
    }

private:
    R (*f)(Args...);
};

Live example

like image 74
Jarod42 Avatar answered Oct 08 '22 14:10

Jarod42