Для boost :: ref не найдено соответствующей ошибки вызова, но не с std :: ref

Я написал некоторый код, который подсчитывает количество элементов вектора с помощью функтора и ref а также bind шаблоны из boost:: или же std:: (для C ++ 11) пространства имен. Я использую #define переключаться между boost:: а также std:: Пространства имен. Я использую версию Boost 1.53, и моя команда компиляции g++ test.cpp -std=c++11, Я пытался с gcc версий 4.7.2 и 4.6.3, и я получаю одинаковые ошибки с обоими.

У меня есть 3 вопроса:

  1. Я не понимаю ошибку, которая генерируется для примера 2.
  2. Можно ли сделать такой код переносимым, просто переключая пространства имен?
  3. Есть хороший справочник, подробно описывающий различия между std а также boost версии bind, ref а также function? (Я видел этот вопрос, но ответы не упоминают ref или же function)

Спасибо!

Постскриптум Пример только иллюстрирует мою проблему, я знаю о size() за std::vector 🙂

//#define USE_STD

#ifdef USE_STD
#include <functional>
using namespace std::placeholders;
namespace impl = std;
#else
#include <boost/version.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
namespace impl = boost;
#endif

#include <iostream>
#include <algorithm>
#include <vector>

class Item {
int id_;

public:
Item(int id) : id_(id) {};
};

template <typename ITEM>
class Counter {
int count_;

public:
// typedef void result_type; // adding this fixes Example 3 when impl=boost
Counter() : count_(0) {};
void operator()(ITEM* item) {count_++;}
int operator()() {return count_;}
};

//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
#ifndef USE_STD
std::cout << "BOOST_LIB_VERSION=" << BOOST_LIB_VERSION << std::endl;
#endif

// allocate
typedef std::vector<Item*> ItemVec;
ItemVec vec;
for (int i = 0; i < 9; ++i) {vec.push_back(new Item(i));}

// Example 1, works for BOTH
Counter<Item> f1;
f1 = std::for_each(vec.begin(), vec.end(), f1);
std::cout << "f1()=" << f1() << std::endl;

// Example 2, works with impl=std ONLY
// COMPILE ERROR with impl=boost: "no match for call to ‘(boost::reference_wrapper<Counter<Item> >) (Item*&)’"Counter<Item> f2;
std::for_each(vec.begin(), vec.end(), impl::ref(f2));
std::cout << "f2()=" <<  f2() << std::endl;

// Example 3, works with impl=std ONLY
// COMPILE ERROR with impl=boost "no type named ‘result_type’ in ‘class Counter<Item>’"// this can fixed by adding the typedef described above
Counter<Item> f3;
std::for_each(vec.begin(), vec.end(), impl::bind(impl::ref(f3), _1));
std::cout << "f3()=" << f3() << std::endl;

// clean up
for (ItemVec::iterator it = vec.begin(); it != vec.end(); ++it) {
delete *it;
}
vec.clear();

return 0;
}

6

Решение

Пример 2 терпит неудачу, потому что boost::reference_wrapper не имеет член operator() который передает аргумент (ы), В отличие от std::reference_wrapper, Как таковой, он полезен только для передачи нормальных аргументов по ссылке, а не функций или функторов, которые должны вызываться.

Пример 3 терпит неудачу, потому что Boost.Bind полагается на определенный протокол, чтобы получить тип результата функции или функтора, который вы передаете, если вы используете версию без явного типа возвращаемого значения. Если вы передадите ему указатель на функцию или указатель на член-функцию, объект связывателя с возвращаемым значением имеет вложенный result_type установите тип возврата указанного PTF или PTMF. Если вы передаете функтор, он нуждается во вложенном result_type,
std::bind, с другой стороны, просто не имеет вложенных result_type если у вашего функтора его нет.

Обратите внимание, что, как я уже сказал, вы можете явно указать тип результата для обоих boost::bind а также std::bind:

std::for_each(vec.begin(), vec.end(), impl::bind<void>(impl::ref(f3), _1));
//                                              ^^^^^^

Который исправляет пример и компилирует его.

4

Другие решения

std::ref имеет 1 главное преимущество перед boost::ref: Это обеспечивает идеальную отправку operator(), который перенаправит вызов на содержащуюся ссылку.

boost::ref практически не может сделать это, так как это потребует значительного количества перегрузок. Чтобы позволить это, однако, boost::bind (и несколько других классов) все обеспечивают специальную обработку для boost::reference_wrapper,

2

По вопросам рекламы [email protected]