Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic templates - how can I create type, that stores passed arguments

So suppose, that I have got a class, that contains functional object and in the constructor call I pass arguments, that are to be passed to the functional object some time later. Something like:

class Binder{
public:
    Binder(functional_object, listOfParameters);
    callFunctionalObject(); // calls functional object with given list of parameters
};

Before C++11 I could not use Variadic templates, so one would do:

struct none{};

template <typename T1, typename T2=none, typename T3=none>
class Binder{
public:
    Binder(T1 functionalObject, T2 arg1=none(), T3arg3=none());
    void callFunctionalObject();
private:
    T1 m_functionalObject;
    T2 m_arg1;
    T3 m_arg2;
};

Where callFunctionalobject could be implemented as follows:

template<typename T1, typename T2, typename T3>
void Binder<T1,T2,T3>::callFunctionalObject(){
    callImpl(m_functionalObject, m_arg1, m_arg2);
}

and callImpl would be overloaded to recognize objects of type none to pass proper amount of arguments to the functional object.

Now switching to C++11 I do not know how to implement the fact, that in private section I have got members, to which I have an direct access.

Could anyone explain me the way I can do the same using C++11 or C++14?

like image 931
DawidPi Avatar asked Nov 05 '15 13:11

DawidPi


2 Answers

You should store a std::function and a std::tuple and then call the function on the tuple.

Here a working C++14 solution

#include <iostream>
#include <functional>

template<typename T1, typename ...T>
class Binder
{
public:
    Binder(std::function<T1(T...)> f, std::tuple<T...> t) : m_functional_obj(f), m_parameters(t) {}

    template<std::size_t ...I>
    T1 callImpl(std::index_sequence<I...>) 
    {
        return m_functional_obj(std::get<I>(m_parameters)...);
    }

    T1 callFunctionalObject()
    { 
        return callImpl(std::index_sequence_for<T...>{}); 
    }
private:
    std::function<T1(T...)> m_functional_obj;
    std::tuple<T...>        m_parameters;
};

int test(int i) 
{
    std::cout << "test(" << i << ")" << std::endl;    
    return i + 1;
}

int main()
{
    Binder<int,int> bibi(test, std::make_tuple<int>(2));
    auto res = bibi.callFunctionalObject();
    std::cout << "res is " << res << std::endl;
}

Live code

like image 172
coincoin Avatar answered Oct 05 '22 23:10

coincoin


My example:

// Indices
template <std::size_t... Is>
struct Indices {};

template <std::size_t N, std::size_t... Is>
struct BuildIndices : BuildIndices <N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct BuildIndices<0, Is...> : Indices < Is... > {};

template<class FuncObject, class ... T>
class Binder
{
public:
    Binder(FuncObject funcObject, T... args)
      : m_funcObject(funcObject), m_arguments(std::make_tuple(args...))
    {
    }

    void Call()
    {
      DoCall(BuildIndices<sizeof ... (T)> {});
    }

private:
    template<size_t... Ind>
    void DoCall(Indices<Ind...>)
    {
        return m_funcObject(std::get<Ind>(m_arguments)...);
    }

    FuncObject m_funcObject;
    std::tuple<T...> m_arguments;
};

void Foo(int, char)
{
}

int main()
{
    Binder<void(*)(int, char), int, char> f(Foo, 1, 'd');
    f.Call();

    return 0;
}
like image 42
Hsilgos Avatar answered Oct 05 '22 23:10

Hsilgos