4

I have a set of boost::shared_ptr which I want to be ordered and uniqued not by the shared pointers but by the strings. Do I have to provide a new comparison function getting shared pointers and comparing the contents or there is such a comparator already exists that I can use?

2 Answers 2

4

That's pretty specific, so you'll probably need a custom comparator.

This should work:

struct pointercompare
{
    bool operator()(const boost::shared_ptr<std::string>& a, const boost::shared_ptr<std::string>& b)
    {
        return (*a)>(*b);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I would write a general way of wrapping predicates and iterators that maps value-semantics onto any pointer-like owner.

This then becomes completely general and re-usable.

Simple version here

Bonus code below introduces a complete library for this kind of thing

#include <utility>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <algorithm>

template<class Comp> 
struct pointee
{
  pointee(Comp comp = Comp()) : _comp(comp) {}

  template<class APtr, class BPtr>
    bool operator()(const APtr& a, const BPtr& b)
    {
        return _comp(*a, *b);
    }

  Comp _comp;
};



int main()
{
  std::vector<boost::shared_ptr<int>> v;

  std::sort(v.begin(), v.end(), pointee<std::less<>>());
  std::sort(v.begin(), v.end(), pointee<std::greater<>>());

}

For bonus points...

#include <utility>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <algorithm>
#include <functional>


template<class T, class X, class Y>
struct is_binary_op
{
    template<class U> static auto test(U* p) -> decltype((*p)(std::declval<X>(), std::declval<Y>()), void(), std::true_type());
    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr bool value = decltype(test((T*)0))::value;
};

template<class T, class X, class Y> static constexpr bool IsBinaryOp = is_binary_op<T, X, Y>::value;

template<class T, class X>
struct is_unary_op
{
    template<class U> static auto test(U* p) -> decltype((*p)(std::declval<X>()), void(), std::true_type());
    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr bool value = decltype(test((T*)0))::value;
};
template<class T, class X> static constexpr bool IsUnaryOp = is_unary_op<T, X>::value;

namespace detail {
    template<class Comp>
    struct pointee
    {
        pointee(Comp comp = Comp()) : _comp(comp) {}

        template<
        class APtr,
        class BPtr
        >
        auto operator()(const APtr& a, const BPtr& b) const
        -> std::enable_if_t<
        IsBinaryOp<Comp, decltype(*a), decltype(*b)>
        , bool>
        {
            return _comp(*a, *b);
        }

        template<
        class APtr
        >
        auto operator()(const APtr& a) const
        -> std::enable_if_t<
        IsUnaryOp<Comp, decltype(*a)>
        , bool>
        {
            return _comp(*a);
        }

        Comp _comp;
    };

    template<class Iter>
    struct deref_iter : Iter
    {
        deref_iter(Iter iter) : Iter(iter) {}

        auto& operator*() const {
            return **static_cast<const Iter&>(*this);
        }
    };
}

template<class Pred>
auto pointee(Pred&& pred)
{
    return detail::pointee<std::decay_t<Pred>>(std::forward<Pred>(pred));
}

template<class Iter>
auto deref_pointee(Iter&& iter)
{
    return detail::deref_iter<std::decay_t<Iter>>(std::forward<Iter>(iter));
}


int main()
{
    std::vector<boost::shared_ptr<int>> v;

    // sort using the less predicate on the pointee
    std::sort(v.begin(), v.end(), pointee(std::less<>()));

    // sort using the greater predicate on the pointee
    std::sort(v.begin(), v.end(), pointee(std::greater<>()));

    // apply a unary predicate to every pointee
    std::for_each(v.begin(), v.end(), pointee(std::logical_not<>()));

    // transform the pointees by binding a binary predicate to a value and
    // turning it into a unary predicate that adds 6
    std::transform(v.begin(), v.end(), 
                   deref_pointee(v.begin()), 
                   pointee(std::bind(std::plus<>(), 6, std::placeholders::_1)));

}

Comments

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.