开发者

C++ wrap a generic std::tr1::function with another function

How can I wrap a generic C++ std::tr1::function object with another function such that this function executes first followed by the wrapped function? I've tried:

#include <tr1/functional>

template <typename T>
int wrapped(const std::tr1::function<int(T)>& f, T t)
{
  return f(t);
}

template <typename T>
std::tr1::function<int(T)开发者_如何学Go> wrap(const std::tr1::function<int(T)>& f)
{
  return std::tr1::bind(&wrapped, f, std::tr1::placeholders::_1);
}

int foo(int i) { return i; }

int main(int argc, char** argv)
{
  std::tr1::function<int(int)> f =
    wrap(std::tr1::bind(&foo, std::tr1::placeholders::_1));
  f(1);
  return 0;
}

But this returns with the compiler error (g++):

wrap.cpp: In function ‘int main(int, char**)’:
wrap.cpp:22: error: no matching function for call to ‘wrap(std::tr1::_Bind<int (* ()(std::tr1::_Placeholder<1>))(int)>)’


I see two problems in your code. First, wrapped is not a function, it is a function template, and as such it doesn't exist in the generated program. You can't take an address of a function template. You should instead specify an instantiation of this template to take address of:

template <typename T>
std::tr1::function<int(T)> wrap(const std::tr1::function<int(T)>& f)
{
  return std::tr1::bind(&wrapped<T>, f, std::tr1::placeholders::_1);
}

Second (and thats what your compiler is trying to tell you) you must explicitly specify a template parameter when calling wrap. The compiler can't deduce tha parameter from supplied arguments.

std::tr1::function<int(int)> f =
  wrap<int>(std::tr1::bind(&foo, std::tr1::placeholders::_1));

I don't really understand how std::bind or tr1::bind works on the inside. But I understand that the returned type is very different from a simple function pointer, and as such doesn't allow the compiler to clearly read the type for template parameter deduction. So in these situations you need to specify the type explicitly.


There are two problems with this code. One is easily fixed, the other is not so easily.

#include <tr1/functional>

template <typename T>
int wrapped(const std::tr1::function<int(T)>& f, T t)
{
  return f(t);
}

template <typename T>
std::tr1::function<int(T)> wrap(const std::tr1::function<int(T)>& f)
{
  return std::tr1::bind(&wrapped<T>, f, std::tr1::placeholders::_1); // <- prob 1
}

int foo(int i) { return i; }

int main(int argc, char** argv)
{
  std::tr1::function<int(int)> f =
    wrap(std::tr1::function<int(int)>(std::tr1::bind(&foo,    // <- prob 2
                               std::tr1::placeholders::_1))); 
  f(1);
  return 0;
}
  1. (a small problem) wrapped is a function template and as such cannot be bound. You need a function here. Fortunately you can just specify wrapped<T>.
  2. (a bigger problem) bind does not return an std::tr1::function<>, it returns some other function object. You cannot call a function template that accepts std::tr1::function<> with that object, because there are no user-defined argument conversions for function templates. You need to do the conversion yourself, explicitly. I'm not sure you can eliminate this without going all the way to C++11. In C++11 you can use auto and postfix result type notation to rewrite wrap so it does accept anything, not just a function<int(T)>.

EDIT Fiktik is right in that it is enough to say wrap<int>. Implicit argument conversion does work with it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜