0

I have a problem trying to convert my C++11 code snippet to boost.

Let's suppose I have a simple class:

class C
{

public:

    typedef std::vector<std::string> Info;

public:

    explicit C(Info const& info)
        : info_(info)
    {}

    std::string text(Info::size_type i) const
    {
        return info_[i];
    }

private:

    Info info_;

};

Now if I have a vector of C classes I would like to get the maximum width of a specific C::Info element using std::max_element algorithm.

With C++11 lambdas I could do it the following way:

C::Info::size_type const Info_0 = 0;
C::Info::size_type const Info_1 = 1;
C::Info::size_type const Info_2 = 2;

int get_max_width(std::vector<C> const& c_vec, C::Info::size_type info_n)
{
    std::vector<C>::const_iterator max = std::max_element(c_vec.cbegin(), c_vec.cend(),
        [info_n](C const& lhs, C const& rhs)
        { return lhs.text(info_n).length() < rhs.text(info_n).length(); });

    return max != c_vec.end() ? max->text(info_n).length() : 0;
}

But the problem is that I can't use C++11, so I have to go with boost.

At the moment, the code I was able to come up with looks as follows:

int get_max_width(std::vector<C> const& c_vec, C::Info::size_type info_n)
{
    std::vector<C>::const_iterator max = std::max_element(c_vec.cbegin(), c_vec.cend(),
        boost::lambda::bind(&C::text, boost::lambda::_1, boost::lambda::var(info_n)) <
        boost::lambda::bind(&C::text, boost::lambda::_2, boost::lambda::var(info_n)));

    return max != c_vec.end() ? max->text(info_n).length() : 0;
}

Though it's clearly not what I want. The comparison is performed on the std::string objects, and I'm stuck trying to figure out how to call that length() function...

Your help is quite appreciated.

4
  • 6
    Pardon me, but why bother? You can just define a proper functor to do the same job. Commented Jul 23, 2014 at 19:58
  • @40two The drawback of the functor solution is that C++03 required types used for template arguments to have external linkage. This means the functor cannot be defined locally within get_max_width(). Not a huge deal, but more of an annoying restriction. Commented Jul 23, 2014 at 22:04
  • @Praetorian I agree, it just seems an overkill to me when there's a "nasty" alternative but nevertheless cheaper one Commented Jul 23, 2014 at 23:01
  • @40two, well, it was more like an educational approach to try lambdas. Though your point is correct, yes. Commented Jul 24, 2014 at 6:43

2 Answers 2

4

Here's a C++03 solution that uses Boost.Phoenix

#include <functional>
#include <boost/phoenix.hpp>

int get_max_width(std::vector<C> const& c_vec, C::Info::size_type info_n)
{
    namespace phx = boost::phoenix;
    using namespace phx::arg_names;

    std::vector<C>::const_iterator max = std::max_element(c_vec.begin(), c_vec.end(),
        phx::bind(std::mem_fun_ref(&std::string::length), phx::bind(&C::text, arg1, phx::val(info_n))) < 
        phx::bind(std::mem_fun_ref(&std::string::length), phx::bind(&C::text, arg2, phx::val(info_n)))
      );

    return max != c_vec.end() ? max->text(info_n).length() : 0;
}

I haven't done too much testing with it, but it seems to work here.

Sign up to request clarification or add additional context in comments.

2 Comments

I can't use phoenix due to the project limitations, but thanks for the hint.
Q: "Implement using boost" A: implementation using boost OP: "I can't use Boost Phoenix". WAAAT?
3

Not necessarily the answer you are asking for, but for a non c++11 approach it is useful to know that lambda expressions are similar to structs with a function operator.

So your example could be implemented something like this:

struct lambda_max
{
    const C::Info::size_type& info_n;

    lambda_max(const C::Info::size_type& info_n):info_n(info_n) {}

    bool operator()(C const& lhs, C const& rhs) const
    {
        return lhs.text(info_n).length() < rhs.text(info_n).length();
    }
};

int get_max_width(std::vector<C> const& c_vec, C::Info::size_type info_n)
{
    std::vector<C>::const_iterator max = std::max_element(c_vec.cbegin(), c_vec.cend(),
        lambda_max(info_n));

    return max != c_vec.end() ? max->text(info_n).length() : 0;
}

1 Comment

Your solution suits well. Plus: the simpler - the better. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.