Traditional task of iterating trough key set of std::map
led me to another mess which seems not to be disscused here yet.
In short, this code does not compile (C++11 is heavily used):
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);
Error message is as follows.
no type named 'result_type' in 'struct std::_Bind<std::_Mem_fn<int std::pair<int, int>::*>(std::_Placeholder<1>)>'
At the same time, changing std::bind
to boost::bind
fixes the problem. But there is a code convention in my project that we use std::bind
only.
Any suggestions what to do with this? (Should I write bugreport to the Boost team?)
There are better ways to iterate over the keys of a std::map
(or any container whose value_type
is pair<T,U>
), namely Boost.Range's map_keys
adaptor (there's also a 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 << " ";
}
}
But back to your problem: All Boost libraries use the Boost.Utility function result_of
, which won't fall back to std::result_of
for whatever reason, and also won't use decltype
if it's available without you telling it to. You do so by putting #define BOOST_RESULT_OF_USE_DECLTYPE
before the first Boost include.
That, however, still didn't make your code compile with Clang 3.1 SVN + libc++. Here's the code I used:
#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);
}
Compiled with:
clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic -Ipath/to/boost -Wno-mismatched-tags t.cpp
GCC 4.7 seems to accept this just fine, so I guess it's a bug in libc++.
It seems you need to define BOOST_RESULT_OF_USE_DECLTYPE before including the boost library to actually use the C++11 method to get the result type, instead of relying on the legacy result_type
member. This compiles fine on g++ 4.6 and 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);
}
See the discussion thread http://lists.boost.org/boost-users/2012/01/72856.php to know why it is not enabled by default.
You could also workaround by using std::mem_fn
instead of std::bind
,
auto choose_first = std::mem_fn(&Pair::first);
which does define those legacy type members (§20.8.10/2). Since std::mem_fn
is still part of the standard library I believe there's no problem using it in your team… ?
As a last resort, you could always use the C++03 way to declare a function object (of course we knew std::unary_function
is deprecated):
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With