5

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?

DawidPi
  • 2,285
  • 2
  • 19
  • 41

3 Answers3

7

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

coincoin
  • 4,595
  • 3
  • 23
  • 47
  • 2
    I thought of something like this, but wouldn't functionalObject then get one touple in the parameters instead of normal list of parameters? – DawidPi Nov 05 '15 at 13:45
  • 2
    Unpacking tuple parameters needs a little bit of work trying to get a live code solution for you :) – coincoin Nov 05 '15 at 13:58
  • 1
    @DawidPi Updated a C++14 solution using `std::index_sequence` – coincoin Nov 05 '15 at 14:10
4

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;
}
Hsilgos
  • 71
  • 1
  • 9
  • 1
    This is good, plus in C++14 you don't need your own `Indices` and `BuildIndices` classes any more. – SirGuy Nov 05 '15 at 14:17
2

The simplest way is to store an std::function object with already-set arguments using std::bind:

class Binder{
public:
    template <typename T1, typename... T2>
    Binder(T1 functionalObject, T2... args) : f(std::bind(functionalObject, args...)) {}
    void callFunctionalObject() { f(); }
private:
    std::function<void()> f;
};

void foo(int n, std::string s) {
    std::cout << n << " " << s << std::endl;
}

int main()
{
    Binder b(foo, 42, "test");
    b.callFunctionalObject();
}

If you need something more advanced, then you might want to store the function arguments in and std::tuple and then use some template magic to unwrap it, but please specify what exactly do you need in the question.

P.S. See also "unpacking" a tuple to call a matching function pointer

Community
  • 1
  • 1
Petr
  • 9,812
  • 1
  • 28
  • 52
  • Ok std::bind seems ok and easy way, but still I do not know what kind of mechanism is laying behind this. I should try to look for std::bind implementation then. What I am looking for is the same functionality as code give n in question but more flexible (maximum number of parameters is not set up from the start) using Variadic Templates. – DawidPi Nov 05 '15 at 14:03
  • 1
    I don't think you need the template parameters at the class level, you could just make the constructor a template and people could just use `Binder b(foo, 32, "test");`. – SirGuy Nov 05 '15 at 14:20
  • 1
    This then becomes an advantage of using `std::bind` over storing the parameters manually in a `std::tuple`. Whether that advantage is meaningful to the OP or not is another matter though. – SirGuy Nov 05 '15 at 14:24