2

I have come upon this interesting solution (here with an example here) to make a std::bind type function without having to explicitly put placeholders.

Quest

To implement a similar bind function without the capability to put values in the bind call (I don't need it.) and to add the capability to call this new bind function to bind a member pointer.

What I managed to do

So I figured out how to use a dummy std::function to get the function's signature.
I also figured out how to remove the capability of adding values to the bins call.

So here is the code I have:

#include <functional>
#include <type_traits>
#include <utility>

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

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

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<int I> struct placeholder{};

namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
    template<std::size_t... Is, class Fn, class... Args>
    auto my_bind(indices<Is...>, Fn const &f, Fn *i, Args&&... args) 
        -> decltype(std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
        return std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
    }
}

template<class Ret, class... FArgs, class Fn, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args) 
        -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){

    return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...);
}


#include <iostream>
struct tmp{
    void testt(int var1, int var2){
        std::cout << var1 << " " << var2 << std::endl;
    }
};

int main(){

    tmp TMP;
    auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
    f3(22, 23);

}  

Problem

I tried to pass the member pointer to the template however I'm getting compiler errors. (The problem seems related to the passing of the member pointer) I tried other methods of passing a member pointer such as depicted here and here however I have not gained any progress using these methods.

Here are the errors:

g++ -std=c++11 -Wall -W -pedantic -O2 hello-cpp-world.cc -o hello-cpp-world
hello-cpp-world.cc: In function ‘int main()’:
hello-cpp-world.cc:68:73: error: no matching function for call to ‘my_bind(std::function<void(int, int)>, void (tmp::*)(int, int), tmp*)’
     auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
                                                                         ^
hello-cpp-world.cc:68:73: note: candidate is:
hello-cpp-world.cc:48:6: note: template<class Ret, class ... FArgs, class Fn, class ... Args> decltype (detail::my_bind(build_indices<(sizeof (FArgs ...) - sizeof (Args ...))>{}, f, (& i), (forward<Args>)(my_bind::args)...)) my_bind(std::function<_Res(_ArgTypes ...)>, const Fn&, Fn*, Args&& ...)
 auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args) -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){
      ^
hello-cpp-world.cc:48:6: note:   template argument deduction/substitution failed:
hello-cpp-world.cc:68:73: note:   deduced conflicting types for parameter ‘Fn’ (‘void (tmp::*)(int, int)’ and ‘tmp’)
     auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
                                                                         ^
make: *** [hello-cpp-world] Error 1

Question

  • Is what I am trying to achieve even possible? (Although I am quite certain it is)
  • If so, how can this be fixed?
Community
  • 1
  • 1
Cyberunner23
  • 128
  • 1
  • 7

1 Answers1

2

Your code has two key problems:

  1. You keep taking the address of the object you want to call a member function on. Once the entity is a pointer, taking the address of it won't do you much good.
  2. A member function pointer and its first argument obvious have different types. Either you'll need to provide a proper signature of it, you'd extract the first argument type from the member function pointer type, or you leave the corresponding argument type unconstrained and have the type system sort out invalid uses. The latter approach also has the advantage that you could pass reference and smart pointers.

Here is a patched up version of your code which makes it compile:

#include <functional>
#include <type_traits>
#include <utility>

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

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

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<int I> struct placeholder{};

namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
    template<std::size_t... Is, class Ret, class Fn, class... MArgs, class... Args>
    auto my_bind(indices<Is...>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args) 
        -> decltype(std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
        return std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
    }
}

template<class Ret, class... FArgs, class Fn, class... MArgs, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args) 
        -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...)){

    return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...);
}


#include <iostream>
struct tmp{
    void testt(int var1, int var2){
        std::cout << var1 << " " << var2 << std::endl;
    }
};

int main(){

    tmp TMP;
    auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
    f3(22, 23);

}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thanks for the help! Now I need to make a std::map which can contain functions binded by this and to be able to contain binded functions with different signatures... Any suggestions? – Cyberunner23 Mar 15 '15 at 13:50
  • Never mind that... With a little research, boost::any should help me with this, I need to test it though. – Cyberunner23 Mar 15 '15 at 14:01