boost :: transform_iterator не работает с std :: bind (& Pair :: first, _1)? - PullRequest
4 голосов
/ 22 марта 2012

Традиционная задача итерации набора ключей через std::map привела меня к другому беспорядку, который, похоже, еще не рассмотрен здесь.

Короче говоря, этот код не компилируется (C ++ 11 интенсивно используется):

typedef std::pair<int, int> Pair;
vector<Pair> v {Pair(1,2), Pair(2,3)};
using namespace std::placeholders;
auto choose_first = std::bind(&Pair::first, _1);
boost::make_transform_iterator(v.begin(), choose_first);

Сообщение об ошибке выглядит следующим образом.

no type named 'result_type' in 'struct std::_Bind<std::_Mem_fn<int std::pair<int, int>::*>(std::_Placeholder<1>)>' 

В то же время, изменение std::bind на boost::bind устраняет проблему. Но в моем проекте есть соглашение о коде, в котором мы используем только std::bind.

Есть предложения, что с этим делать? (Должен ли я написать отчет об ошибке в команду Boost?)

Ответы [ 2 ]

4 голосов
/ 22 марта 2012

Существуют лучшие способы перебора ключей std::map (или любого контейнера, для которого value_type равен pair<T,U>), а именно Boost.Range 'map_keys*Адаптер 1008 * (есть также map_values one):

#include <boost/range/adaptor/map.hpp>
#include <utility>
#include <vector>
#include <iostream>

int main(){
  typedef std::pair<int, int> Pair;
  std::vector<Pair> v {Pair(1,2), Pair(2,3)};
  for(auto& first : v | boost::adaptors::map_keys){
    std::cout << first << " ";
  }
}

Но вернемся к вашей проблеме: все библиотеки Boost используют функцию Boost.Utility result_of, который по любой причине не вернется к std::result_of, а также не будет использовать decltype, если он доступен без вашего ведома.Вы делаете это, помещая #define BOOST_RESULT_OF_USE_DECLTYPE перед первым включением Boost.

Это, тем не менее, не позволило компилировать ваш код с Clang 3.1 SVN + libc ++.Вот код, который я использовал:

#define BOOST_RESULT_OF_USE_DECLTYPE
#include <boost/iterator/transform_iterator.hpp>
#include <utility>
#include <vector>
#include <functional>

int main(){
  typedef std::pair<int, int> Pair;
  std::vector<Pair> v {Pair(1,2), Pair(2,3)};
  using namespace std::placeholders;
  auto choose_first = std::bind(&Pair::first, _1);
  boost::make_transform_iterator(v.begin(), choose_first);
}

Скомпилировано с:

clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic -Ipath/to/boost -Wno-mismatched-tags t.cpp

GCC 4.7, кажется, принимает это очень хорошо, поэтому я предполагаю, что это ошибка в libc ++.

1 голос
/ 22 марта 2012

Кажется, вам нужно определить BOOST_RESULT_OF_USE_DECLTYPE перед тем, как включать библиотеку буста, чтобы фактически использовать метод C ++ 11 для получения типа результата, вместо того чтобы полагаться на устаревший член result_type. Это прекрасно компилируется на g ++ 4.6 и 4.8:

#define BOOST_RESULT_OF_USE_DECLTYPE
// ^

#include <vector>
#include <boost/iterator/transform_iterator.hpp>
#include <functional>

int main()
{

typedef std::pair<int, int> Pair;
std::vector<Pair> v {Pair(1,2), Pair(2,3)};
using namespace std::placeholders;
auto choose_first = std::bind(&Pair::first, _1);
boost::make_transform_iterator(v.begin(), choose_first);

}

См. Ветку обсуждения http://lists.boost.org/boost-users/2012/01/72856.php, чтобы узнать, почему она не включена по умолчанию.


Вы также можете обойти это, используя std::mem_fn вместо std::bind,

auto choose_first = std::mem_fn(&Pair::first);

, который определяет те устаревшие члены типа (§20.8.10 / 2). Поскольку std::mem_fn все еще является частью стандартной библиотеки, я полагаю, что нет проблем с ее использованием в вашей команде ...?


В качестве последнего средства вы всегда можете использовать способ C ++ 03 для объявления объекта функции (конечно, мы знали, что std::unary_function устарела):

template <typename T>
struct FirstChooser :
        public std::unary_function<const T&, typename T::first_type>
{
    typename T::first_type operator()(const T& input) const
    {
        return input.first;
    }
};

...

FirstChooser<Pair> choose_first;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...