Adi Shavit
Adi Shavit

Reputation: 17265

boost::bind() with template functions

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))();

Upvotes: 0

Views: 619

Answers (2)

Adi Shavit
Adi Shavit

Reputation: 17265

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.

Upvotes: 0

zaufi
zaufi

Reputation: 7119

#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()

Upvotes: 1

Related Questions