通过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团队吗?)
答案 0 :(得分:4)
有更好的方法来迭代std::map
(或value_type
为pair<T,U>
)的任何容器的键,即Boost.Range的map_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;