开发者

On reference_wrapper and callable objects

开发者 https://www.devze.com 2022-12-30 04:13 出处:网络
Given the following callable object: struct callable : public std::unary_function <void, void> { void

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;
    }
};
0

精彩评论

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

关注公众号