On reference_wrapper and callable objects
Given the following callable object:
struct callable : public std::unary_function <void, void>
{
void
operator()() const
{
std::cout << "hello world" << std::endl;
}
};
a std::tr1::reference_wrapper<>
calls through it:
callable obj;
std::tr1::ref(obj)();
Instead, when the operator()
accepts an argument:
开发者_StackOverflow社区struct callable : public std::unary_function <int, void>
{
void
operator()(int n) const
{
std::cout << n << std::endl;
}
};
std::tr1::bind
accepts a reference_wrapper to it as a callable wrapper...
callable obj;
std::tr1::bind( std::tr1::ref(obj), 42 )();
but what's wrong with this?
std::tr1::ref(obj)(42);
g++-4.4 fails to compile with the following error:
test.cpp:17: error: no match for call to ‘(std::tr1::reference_wrapper<const callable>) (int)’
/usr/include/c++/4.4/tr1_impl/functional:462: note: candidates are: typename std::tr1::result_of<typename std::tr1::_Function_to_function_pointer<_Tp, std::tr1::is_function::value>::type(_Args ...)>::type std::tr1::reference_wrapper<_Tp>::operator()(_Args& ...) const [with _Args = int, _Tp = const callable]
The implementation of tr1 reference_wrapper of g++-4.4 is equipped with the following operator:
template<typename... _Args>
typename result_of<_M_func_type(_Args...)>::type
operator()(_Args&... __args) const
{
return __invoke(get(), __args...);
}
It takes arguments by reference. Hence the reference_wrapper cannot be invoked passing an r-value argument:
std::tr1::ref(obj)(42);
instead:
int arg = 42;
std::tr1::ref(obj)(arg);
works just fine.
std::tr1::bind( std::tr1::ref(obj), 42 )()
works because bind takes the arguments by copy.
What makes you sure there's anything wrong with it? I believe this should work:
#include <functional>
#include <iostream>
struct callable : public std::unary_function <int, void>
{
void
operator()(int n) const
{
std::cout << n << std::endl;
}
};
int main() {
callable obj;
std::tr1::ref(obj)(42);
return 0;
}
At least with MS VC++ 9, it compiles and executes just fine, and offhand I can't see any reason it shouldn't work with other compilers as well.
Edit: Doing some looking at TR1, I take that back. It works with VC++ 9, but I don't think it's really required to work. VC++ 9 doesn't support variable template arguments, so they're supporting this via overloading. Rather deeply buried (<functional>
includes <xawrap>
, which includes <xawrap0>
[which, in turn, includes <xawrap1>
]) is code to generate reference and (importantly) reference to const variants for up to 10 arguments. It's almost certainly the inclusion of the reference to const variants that allows this to work.
First of all, the use of std::unary_function for a null-ary function looks odd. "unary" = takes one argument. I'm not sure whether it's okay to use ArgType=void.
Secondly, you have it backwards. The first template parameter is about the argument type and the second one is about the return type. So, your unary function object should be defined like this:
struct callable : public std::unary_function<int,void>
{
void operator()(int n) const
{
std::cout << n << std::endl;
}
};
精彩评论