Boost :: transform_iterator not working with std :: bind (& Pair :: first, _1)?

The traditional task of retyping std::map keys has led me to another mess, which seems to be not yet scattered.

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); 

The 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 in my project there is a code convention that we use only std::bind .

Any suggestions what to do about it? (Should I write a bugreport to the Boost team?)

+4
source share
2 answers

There are more efficient ways to iterate over std::map keys (or any container whose value_type is pair<T,U> ), namely Boost.Range map_keys adapter (there is also map_values one there):

 #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 result_of function , which will not return to std::result_of for any reason, and also will not use decltype if it is available if you do not report it. You do this by putting #define BOOST_RESULT_OF_USE_DECLTYPE before turning on the first Boost.

This, however, did not compile your code using Clang 3.1 SVN + libC ++. Here is 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 agree with this just fine, so I assume this is a bug in libC ++.

+4
source

It seems you need to define BOOST_RESULT_OF_USE_DECLTYPE before turning on the boost library to actually use the C ++ 11 method to get the result type instead of relying on the deprecated result_type member. This compiles in 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 topic http://lists.boost.org/boost-users/2012/01/72856.php to find out why it is not enabled by default.


You can also use a roundabout way std::mem_fn instead of std::bind ,

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

which defines those elements of the old type (ยง20.8.10 / 2). Since std::mem_fn is still part of the standard library, I believe that your team has no problem using it ...?


As a last resort, you can always use the C ++ 03 method to declare a function object (of course, we knew that std::unary_function 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; 
+1
source

Source: https://habr.com/ru/post/1402899/


All Articles