boost :: transform_iterator不能用于std :: bind(& Pair :: first,_1)?

时间:2012-03-22 13:58:52

标签: c++ boost c++11

通过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

有什么建议怎么办? (我应该把bug报告写给Boost团队吗?)

2 个答案:

答案 0 :(得分:4)

有更好的方法来迭代std::map(或value_typepair<T,U>)的任何容器的键,即Boost.Rangemap_keys适配器(还有一个map_values):

#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 function result_of,无论出于何种原因,它都不会回退到std::result_of,如果可用,也不会使用decltype没有你告诉它。您可以通过在第一个Boost include之前放置#define BOOST_RESULT_OF_USE_DECLTYPE来实现此目的。

但是,仍然没有使用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 :(得分:1)

在包含boost库以实际使用C ++ 11方法获取结果类型之前,似乎需要定义BOOST_RESULT_OF_USE_DECLTYPE,而不是依赖于旧版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;