问题
This question is inspired from another topic which poses this question:
Find the first value greater than user specified value from a map container
which can be solved in several ways. A typical C++03 solution defines a dedicated function (or functor) and pass it to std::find_if
as third argument.
In C++11, one can avoid defining a dedicated function (or functor), and can instead make use of lambda
as:
auto it = std:: find_if(m.begin(), mp.end(),
[n](const std::pair<std::string, int> & x) -> bool
{ return x.second > n; }
);
which is the accepted answer.
I'm still looking for a short and cool solution. If it were a vector, then I just learnt a cool solution which makes use of Boost.Phoenix
and the solution becomes very concise (ideone demo):
std::vector<int> v = ...;
auto it = std::find_if(v.begin(), v.end(), arg1 > 4);
Here arg1
is a functor object defined in boost::phoenix::arg_names
namespace, and the expression arg1>4
evaluates to another functor which then gets passed to std::find_if
.
A quick test is (ideone),
std::cout<< (arg1 > 9)(v) << std::endl; //prints 0 if as v > 9 is false, else 1
//or store the functor first and then use it
const auto & f = arg1 > 9;
std::cout<< f(v) << std::endl; //prints 0 if as v > 9 is false, else 1
My question is, I want to solve the map problem, in a similar way. Is there any such solution? Something like:
auto it = std::find_if(m.begin(),mp.end(), (???).second > n); //m is std::map
Or,
auto it = std::find_if(m.begin(),mp.end(), at<1>(arg1) > n); //m is std::map
For it to work, the expression at<1>(arg1) > 2
has to evaluate to a functor which takes const std::pair &
as argument. My gut feelings tells me that boost has this solution. :-)
回答1:
Indeed, Boost.Fusion and Boost.Phoenix have exactly what you want built-in.
If one includes the necessary header to adapt std::pair<> as a conforming Fusion sequence, then one can use Phoenix's lazy version of boost::fusion::at_c<>
to access std::pair<>::first
or std::pair<>::second
(be sure to #include <boost/phoenix/fusion.hpp>
).
namespace phx = boost::phoenix;
using phx::arg_names::arg1;
auto it = std::find_if(m.begin(), m.end(), phx::at_c<1>(arg1) > n);
EDIT: Full sample, tested with VC++ 2010 SP1 + Boost 1.47.0:
#include <algorithm>
#include <map>
#include <string>
#include <iostream>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/fusion.hpp>
int main()
{
namespace phx = boost::phoenix;
using phx::arg_names::arg1;
std::map<std::string, int> m;
m["foo"] = 1;
m["bar"] = 2;
m["baz"] = 3;
m["qux"] = 4;
m["quux"] = 5;
m["corge"] = 6;
m["grault"] = 7;
m["garply"] = 8;
m["waldo"] = 9;
m["fred"] = 10;
m["plugh"] = 11;
m["xyzzy"] = 12;
m["thud"] = 13;
int const n = 6;
auto it = std::find_if(m.cbegin(), m.cend(), phx::at_c<1>(arg1) > n);
if (it != m.cend())
std::cout << it->first << '\n'; // prints "fred"
}
来源:https://stackoverflow.com/questions/7337414/how-can-i-make-stdfind-if-and-stdmap-work-together-using-some-boost-library