Об объекте reference_wrapper и вызываемых объектах - PullRequest
1 голос
/ 15 мая 2010

Имеется следующий вызываемый объект:

struct callable : public std::unary_function <void, void>
{
    void
    operator()() const
    {
        std::cout << "hello world" << std::endl;
    }
};  

a std::tr1::reference_wrapper<> звонки через него:

callable obj;
std::tr1::ref(obj)();

Вместо этого, когда operator() принимает аргумент:

struct callable : public std::unary_function <int, void>
{
    void
    operator()(int n) const
    {
        std::cout << n << std::endl;
    }
};  

std::tr1::bind принимает reference_wrapper в качестве вызываемой оболочки ...

callable obj;
std::tr1::bind( std::tr1::ref(obj), 42 )();

а что с этим не так?

std::tr1::ref(obj)(42);

g ++ - 4.4 не компилируется со следующей ошибкой:

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]

Ответы [ 3 ]

2 голосов
/ 15 мая 2010

Почему вы уверены, что с этим что-то не так? Я считаю, что это должно работать:

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

По крайней мере, с MS VC ++ 9 он прекрасно компилируется и выполняется, и я не вижу никакой причины, по которой он не должен работать и с другими компиляторами.

Редактировать: Делая некоторые взгляды на TR1, я забираю это обратно. Он работает с VC ++ 9, но я не думаю, что он действительно необходим для работы. VC ++ 9 не поддерживает переменные аргументы шаблона, поэтому они поддерживают это с помощью перегрузки. Довольно глубоко скрыт (<functional> включает <xawrap>, который включает <xawrap0> [который, в свою очередь, включает <xawrap1>]) - это код для генерации ссылки и (что важно) ссылки на константные варианты для до 10 аргументов. Это почти наверняка включает ссылку на константные варианты, которая позволяет это работать.

2 голосов
/ 15 мая 2010

Реализация tr1 reference_wrapper в g ++ - 4.4 оснащена следующим оператором:

  template<typename... _Args>
    typename result_of<_M_func_type(_Args...)>::type
    operator()(_Args&... __args) const
    {
      return __invoke(get(), __args...);
    }

Принимает аргументы по ссылке. Следовательно, reference_wrapper нельзя вызывать, передавая аргумент r-значения:

std::tr1::ref(obj)(42);

вместо

int arg = 42;
std::tr1::ref(obj)(arg);

работает просто отлично.

std::tr1::bind( std::tr1::ref(obj), 42 )() 

работает, потому что bind принимает аргументы копией.

0 голосов
/ 15 мая 2010

Прежде всего, использование std :: unary_function для нулевой функции выглядит странно. "унарный" = принимает один аргумент. Я не уверен, что можно использовать ArgType = void.

Во-вторых, у вас это задом наперед. Первый параметр шаблона относится к типу аргумента, а второй - к типу возвращаемого значения. Итак, ваш унарный объект функции должен быть определен так:

struct callable : public std::unary_function<int,void>
{
    void operator()(int n) const
    {
        std::cout << n << std::endl;
    }
};
...