0

How can I boost::bind() a template function?

I want this code (inspired by the boost::bind bind_as_compose.cpp example) to compile and run. Note the evaluation is different than in the bind_as_compose.cpp example; fff() begins running before kkk():

template<class F> 
void fff(F fun)
{
   std::cout <<  "fff(";
   fun();
   std::cout << ")";
}

void kkk()
{
   std::cout <<  "kkk()";
}

void test()
{
   fff(kkk);             // "Regular" call - OK
   // bind(fff,kkk)();   // Call via bind: Does not compile!!!
}

To print:

fff(kkk())
fff(kkk())

Update: Based on this answer, I got this to work:

void (&fff_ptr)(void(void)) = fff;
boost::bind(fff_ptr, kkk)();

However, this requires me to explicitly specify the instantiation types, which kinds beats the purpose...

Update 2 Ultimately, I wanted to pass the bound object as a nullary callable-type argument to another function like fff(). In this case, what would be the explicit types?

Say I have another template function ggg():

template<class F> 
void ggg(F fun)
{
   std::cout <<  "ggg(";
   fun();
   std::cout << ")";
}

How can I use bind to get this output: fff(ggg(kkk()))?
This does not seem to work:

boost::bind(fff<void()>, boost::bind(ggg<void()>, kkk))();
Community
  • 1
  • 1
Adi Shavit
  • 16,743
  • 5
  • 67
  • 137

2 Answers2

1
#include <iostream>
#include <functional>

template<class F>
void fff(F fun)
{
std::cout << "fff(";
fun();
std::cout << ")" <<  std::endl;
}

void kkk()
{
std::cout << "kkk()";
}

int main()
{
    // "Regular" call - OK
    fff(kkk);
    // you have to specify template parameters:
    std::bind(&fff<void()>, &kkk)();
    return 0;
}

output is:

zaufi@gentop /work/tests $ g++11 -o bind_test bind_test.cc
zaufi@gentop /work/tests $ ./bind_test
fff(kkk())
fff(kkk())

according your second part of the question:

boost::bind(fff, boost::bind(ggg, kkk))();

this wouldn't compile, because the argument of the outer bind is not a void() type! it is actually really complex template that definitely can't be casted to void()

zaufi
  • 6,811
  • 26
  • 34
  • Is there no way to deduce these automatically based on the argument, i.e. `kkk()`? – Adi Shavit Aug 03 '13 at 18:07
  • @AdiShavit no. first of all you are going to take an address of a function! at this point there is no call, no arguments, so you have to specify explicitly what instance of `fff` you want to take address of. – zaufi Aug 03 '13 at 18:15
  • Re: the second part: Exactly. That's why I was looking for a solution with automatic type deduction. – Adi Shavit Aug 03 '13 at 18:30
  • @AdiShavit it would be relatively easy w/ C++11 and `decltype` :) but you may try to experiment w/ boost typeof library – zaufi Aug 03 '13 at 18:32
0

Answering myself... seems like boost::bind is not the way to go here.
I ended up with this:

template <typename Fun>
class FFF_t
{   
public:
   FFF_t(Fun fun): realFun(fun) {}

   void operator()() { invoke(); }

   void invoke() 
   {
      std::cout <<  "fff(";
      realFun();
      std::cout << ")";
   }
private:
   Fun realFun;
};

template<class Fun> 
FFF_t<Fun> fff(Fun fun)
{  return FFF_t<Fun>(fun); }

This allows me to write

fff(fff(kkk))();

which gives fff(fff(kkk())) as expected. bind() can still be used as the inner functor as in fff(fff(bind(some2argFun,1,2))))().

What I couldn't figure out was how to make the return type of invoke() and operator()()'s dependent on the return type of Fun() (void in the example).

Hat-tip to @Igor R. for his comment that sent me in this direction.

Adi Shavit
  • 16,743
  • 5
  • 67
  • 137