Для 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 вопроса:
- Я не понимаю ошибку, которая генерируется для примера 2.
- Можно ли сделать такой код переносимым, просто переключая пространства имен?
- Есть хороший справочник, подробно описывающий различия между
std
а такжеboost
версииbind
,ref
а такжеfunction
? (Я видел этот вопрос, но ответы не упоминаютref
или жеfunction
)
Спасибо!
PS Пример просто иллюстрирует мою проблему, я знаю о 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;
}
2 ответа
Пример 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));
// ^^^^^^
Который исправляет пример и компилирует его.
std::ref
имеет 1 главное преимущество перед boost::ref
: Это обеспечивает идеальную отправку operator()
, который перенаправит вызов на содержащуюся ссылку.
boost::ref
практически не может сделать это, так как это потребует значительного количества перегрузок. Чтобы позволить это, однако, boost::bind
(и несколько других классов) все обеспечивают специальную обработку для boost::reference_wrapper
,