Как я могу заставить std :: find_if и std :: map работать вместе, используя некоторую библиотеку boost? - PullRequest
6 голосов
/ 07 сентября 2011

Этот вопрос основан на другой теме , которая задает этот вопрос:

Найти первое значение, большее, чем указанное пользователем, из контейнера карты

, который можно решить несколькими способами.Типичное решение C ++ 03 определяет выделенную функцию (или функтор) и передает ее std::find_if в качестве третьего аргумента.

В C ++ 11 можно избежать определения выделенного функция (или функтор), и вместо этого может использовать lambda как:

auto it = std:: find_if(m.begin(), mp.end(), 
                    [n](const std::pair<std::string, int> & x) -> bool
                       { return x.second > n; }
                   );

, что является принятым ответом .

Я все еще ищукороткое и классное решение.Если бы это был вектор, то я только что узнал классное решение, которое использует Boost.Phoenix, и решение становится очень кратким ( ideone demo ):

std::vector<int> v = ...;
auto it = std::find_if(v.begin(), v.end(), arg1 > 4);

Здесь arg1является объектом функтора, определенным в boost::phoenix::arg_names пространстве имен, а выражение arg1>4 вычисляется в другом функторе, который затем передается в std::find_if.

Быстрый тест ( 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

Мой вопрос: я хочу решить проблему с картой аналогичным образом.Есть ли такое решение?Что-то вроде:

auto it = std::find_if(m.begin(),mp.end(), (???).second > n); //m is std::map

Или

auto it = std::find_if(m.begin(),mp.end(), at<1>(arg1) > n);  //m is std::map

Для того, чтобы это работало, выражение at<1>(arg1) > 2 должно вычисляться для функтора, который принимает const std::pair & в качестве аргумента.Мои интуитивные чувства говорят мне, что у Boost есть это решение.: -)

1 Ответ

9 голосов
/ 07 сентября 2011

Действительно, Boost.Fusion и Boost.Phoenix имеют именно то, что вы хотите встроить.

Если включить необходимый заголовок для , адаптировать std::pair<> как соответствующую последовательность Fusion , то можно использовать ленивую версию Phoenix boost::fusion::at_c<> для доступа к std::pair<>::first или std::pair<>::second (обязательно #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);

РЕДАКТИРОВАТЬ: Полный образец, протестирован с 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"
}
...