binding member functions in a variadic fashion
Asked Answered
H

1

13

I have a member function with a variable number of parameters, stored in a std::function, and I want to bind the instance and get an independent function object.

template <class T, class R, class... Args>
void connect(const T& t, std::function<R(const T&, Args...)> f) {
  std::function<R(Args...)> = /* bind the instance c into the function? */
}

// ...

Class c;
connect(c, &Class::foo);

For a fixed number of arguments I'd use std::bind, but I don't see how to do this for variadic parameters.

Herbie answered 10/8, 2012 at 13:36 Comment(5)
How exactly do you get Args...?Coheir
Okay, I wrote the code differently, hopefully it's more understandable this way.Herbie
Yes, it is. And makes the solution rather easy. :)Coheir
@Coheir That's what I like to hear :DHerbie
When you call connect() you also need to explicitly pass the types that will be used by the template.Quibbling
F
1

I hope this is what you were trying to achieve:

#include <iostream>
#include <cstdarg>
#include <functional>

class Class {
  public:
    void foo(...)
    {
        std::cout << "foo" << std::endl;
    } 
};

template <typename RES_T>
using ClassVarMemFunT = RES_T (Class::*)(...);

// Without typedef:
// template <class... ARGS, class CLASS_T, class RES_T>
// std::function<RES_T(ARGS...)> connect(CLASS_T& object, RES_T (CLASS_T::*funPtr)(...)) 

template <typename... ARGS, typename CLASS_T, typename RES_T>
std::function<RES_T(ARGS...)> connect(CLASS_T& object, ClassVarMemFunT<RES_T> funPtr)
{
    std::function<RES_T(ARGS...)> resultFun = [&object, funPtr](ARGS&&... args) -> RES_T { 
        return (object.*funPtr)(std::forward<ARGS>(args)...);
    };
    return resultFun;
}

int main() {
    Class c;
    auto funPtr1 = connect<int, float>(c, &Class::foo);
    funPtr1(10, 2.f);

    auto funPtr2 = connect<double, float, int>(c, &Class::foo);
    funPtr2(2., 2.f, 10);
    return 0;
}

In my implementation connect expects the actual argument types as template parameters. The connect function returns an std::function that expects arguments with ARGS... types.

connect has two parameters:

  • one for the object that has a variadic function (object).
  • one for the member function pointer that points to the variadic function we would like to call (funPtr).

We cannot use std::bind in the implementation (we could, but it would involve a lot of boilerplate to add as many std::placeholders as we need based on the ARGS).

So I introduce a lambda instead, that expects the actual ARGS typed arguments. We can return the lambda as an std::function and we are good to go.

https://godbolt.org/z/7cx3rcYh8

I created a version that can print out the variadic list as well:

https://godbolt.org/z/nMxj7Wh9j

Filly answered 4/1, 2023 at 11:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.