I would like to modify the following code so that I can sort using objects.
The current code is fine when sorting individual methods that return a single value.
How can I implement using methods that returns a object;
template<typename T, typename M, template<typename> class C = std::less>
struct method_comparer : std::binary_function<T, T, bool>
{
explicit method_comparer(M (T::*p)() const) : p_(p) { }
bool operator ()(T const& lhs, T const& rhs) const
{
return C<M>()((lhs.*p_)(), (rhs.*p_)());
}
private:
M (T::*p_)() const;
};
template<typename T, typename M>
method_comparer<T, M> make_method_comparer(M (T::*p)() const)
{
return method_comparer<T, M>(p);
}
template<template<typename> class C, typename T, typename M>
method_comparer<T, M, C> make_method_comparer2(M (T::*p)() const)
{
return method_comparer<T, M, C>(p);
}
Main.cpp
// works well
std::sort(vec_p2d.begin(),vec_p2d.end(),make_method_comparer(&Point2D::getX));
// Would like to implement this
std::sort(vec_l2d.begin(),vec_l2d.end(),make_method_comparer(&Line2D::getPt1));
getPt1() methods return a Point2D object which contains the values for int x and int y;
AFAICS, you can leave your code as is. The only thing you must define is a comparison operator for Point2D or whatever object you're returning:
class Point2D {
public:
friend bool operator<(const Point2D &p1, const Point2D &p2) { ...; }
...
};
You can also remove your method_comparer class and just give appropriate comparer functions to sort:
bool compare_line_points(const Line2D &l1, const Line2D &l2) {
return l1.getPt1() < l2.getPt1();
}
and
std::sort(vec_l2d.begin(), vec_l2d.end(), compare_line_points);
Depending on your requirements, these are just a bunch of one- or two-liners. No need for templates.
If you may use boost, how about:
std::sort(vec_p2d.begin(), vec_p2d.end(), boost::bind( &Point2D::getX, _1 ) < boost::bind( &Point2D::getX, _2 ) );
&
std::sort(vec_p2d.begin(), vec_p2d.end(), boost::bind( &Point2D::getPt1, _1 ) < boost::bind( &Point2D::getPt1, _2 ) );?
Related
I need to write a comparator builder which can generate a comparator for std:sort. This builder can deal with any generic objects, and take an arbitrary data member of the object in std:vector to sort. so we need to pass in the class data member pointer to comparator_builder's constructor. The usage and the interface of this comparator_builder is shown below:
vector<T> arr;
sort( arr.begin(), arr.end(), comparator_builder( &T::data_memeber ) );
Since we don't know what objects to be sorted is before-hand, we can't know what data member will be in it. We need to also make the class member pointer generic. No idea how to implement it using template. Is there any C++ expert or genius who can give me some guidance?
The following is my code. But they can't be complied even.
template <typename ObjectType, typename MemberType >
class Comparator {
public:
Comparator ( ObjectType::data_address ) {
data_ptr = &data_address
}
bool operator()( ObjectType x, ObjectType y ) {
return x.*data_ptr < y.*data_ptr;
}
MemberType ObjectType::* data_ptr;
};
template <typename ObjectType, typename MemberType >
class Comparator_Builder{
ObjectType::member_address ;
public:
Comparator_Builder( ObjectType::mem_address ) {
member_address = mem_address;
}
Comparator < ObjectType, MemberType ObjectType::* > operator()() {
return Comparator < ObjectType, MemberType ObjectType::* >( member_address );
}
};
You're already most of the way there with your comparator class:
template <typename ObjectType, typename MemberType>
class MemberComparator {
public:
using MemberPtr = MemberType ObjectType::*;
explicit MemberComparator(MemberPtr ptr) : m_ptr(ptr) {}
bool operator()(const ObjectType& x, const ObjectType& y) const {
return x.*m_ptr < y.*m_ptr;
}
private:
MemberPtr m_ptr;
};
Just a few syntax fixes and that's all you need. Constructor template argument deduction also makes this really easy to use in C++17:
std::sort(vec.begin(), vec.end(), MemberComparator(&T::data_member));
If you don't have C++17 you either have to manually specify the template parameters or you can create a template function to do the deduction:
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType ObjectType::*ptr) {
return MemberComparator<ObjectType, MemberType>(ptr);
}
And then use it like this:
std::sort(vec.begin(), vec.end(), GetComparator(&T::data_member));
From the comments:
is it possible that we make argument passed into GetComparator() more generic? so that we can also pass in getter function, which is class function pointer, like this std::sort(vec.begin(), vec.end(), GetComparator(&T:: get_data_member) );?
Yes, we could certainly add implementations for member functions, though you'll start to run into problems if those getters are overloaded. This can be made more generic, however:
template <typename F>
auto GetComparator(F&& func) {
return [f = std::forward<F>(func)](auto&& lhs, auto&& rhs) {
return f(lhs) < f(rhs);
};
}
Now we can do this:
std::sort(vec.begin(), vec.end(), [](const auto &value) { return value.get_data_member(); });
This can likewise replace the member pointer comparator we have above by just doing e.g.:
std::sort(vec.begin(), vec.end(), [](const auto &value) { return value.data_member; });
If you like the member pointer syntax we can add overloads for that and even replace the MemberComparator class entirely:
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType ObjectType::*ptr) {
return [ptr](const ObjectType& lhs, const ObjectType& rhs) {
return lhs.*ptr < rhs.*ptr;
};
}
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType (ObjectType::*ptr)()) {
return [ptr](ObjectType& lhs, ObjectType& rhs) {
return (lhs.*ptr)() < (rhs.*ptr)();
};
}
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType (ObjectType::*ptr)() const) {
return [ptr](const ObjectType& lhs, const ObjectType& rhs) {
return (lhs.*ptr)() < (rhs.*ptr)();
};
}
In a template function a std::vector shall get sorted. T can be a simple type or a std::pair e.g.,
std::vector<double> or
std::vector<std::pair<int,Something> >
When T is a pair then only the first element shall be compared. How can I implement the comparator for the two cases?
I have tried:
template<typename T>
inline bool smaller(const T& a,const T& b)
{
return a<b;
}
template<typename T,typename S>
inline bool smaller(
const std::pair<T,S>& a,
const std::pair<T,S>& b
)
{
return a.first<b.first;
}
template<typename T> inline void function(std::vector<T >& vVec)
{
...bla...
sort(vVec.begin(),vVec.end(),smaller<T>);
...bla...
}
but it does not work this way. I have also tried specialization but I do not find the right syntax to specialize the smaller() function.
You could just wrap it in a lambda:
std::sort(vVec.begin(),vVec.end(), [](const auto& a, const auto& b) { return smaller(a, b); });
One easy work around is to make both of your smaller functions opeator()'s of a smaller struct. Using
struct smaller
{
template<typename T>
bool operator()(const T& a,const T& b)
{
return a < b;
}
template<typename T, typename S>
bool operator() (const std::pair<T, S>& a, const std::pair<T, S>& b)
{
return a.first < b.first;
}
};
allows you to just pass a smaller to sort like
template<typename T> inline void function(std::vector<T >& vVec)
{
sort(vVec.begin(),vVec.end(),smaller{});
}
and in sort overload resolution will kick in on the two operator() smaller has and for any std::vector<std::pair>, the std::pair overload will be called.
Supose I need to write a class which acts as a wrapper for values:
template<typename T>
struct value_wrapper
{
T value;
value_wrapper( const T& v ) : value( v ) {}
//etc...
};
The class is dessigned to be used as an alias of the original value, so if that value was an rvalue, the wrapper holds the value, and if it was an lvalue the wrapper holds a reference to it.
The class is supposed to overload, say, comparison operators and be used in this way:
template<typename T , typename U>
bool f( const T& lhs , const T& rhs )
{
return wrapper( lhs ) == wrapper( rhs );
}
Or this:
int main()
{
int a , b;
bool flag = wrapper( a ) == wrapper( b ) || wrapper( a ) == wrapper( 2 );
}
My question is: Whats the best (efficient) way to implement such thing?
That questions seems to broad, I mean:
How I define the member value? As T& for lvalues, and T for rvalues?
Is there any standard way to write this kind of universal (rvalue and lvalue) alias?
I would simply provide suitable conversion operators:
#include <utility>
#include <type_traits>
template <typename T> struct Wrapper
{
static_assert(!std::is_reference<T>::value, "Do not use a reference type");
using type = T;
T value;
Wrapper(T && t) : value(std::move(t)) {}
Wrapper(T const & t) : value(t) {}
operator T const & () const noexcept { return value; }
operator T & () & noexcept { return value; }
operator T && () && noexcept { return std::move(value); }
// maybe some more CV variants...
};
template <typename U> struct Wrapper<U &>
{
using type = U &;
U & ref;
Wrapper(U & u) : ref(u) {}
operator U & () { return ref; }
};
I'd accompany this with a deducing function:
template <typename T> Wrapper<T> wrap(T && t)
{ return Wrapper<T>(std::forward<T>(t)); }
Example usage:
int n = 10;
bool b = wrap(n) == wrap(5 + 5)
The conversion operators allow you to use whatever operators are defined on the underlying type.
I think Kerrek SB is on the right track by providing a specialization (got my +1 a long time ago), so each case is handled most efficiently.
The problem is you can't just add implicit conversion operators and if you want to provide your own operator overloads, things can become quite tricky.
The solution I came up with tries to deal with this by putting the information which case a certain variable is into a boolean template parameter. Here's the basic framework for the value_wrapper class:
template< typename T, bool >
class value_wrapper
{
private:
T t_; // store a value
public:
explicit value_wrapper( T&& t ) : t_( std::move( t ) ) {}
const T& cref() const { return t_; }
};
template< typename T >
struct value_wrapper< T, true > // specialization for lvalue references
{
private:
const T& t_; // store a reference
public:
explicit value_wrapper( const T& t ) : t_( t ) {}
const T& cref() const { return t_; }
};
The tricky part is the convenience method to wrap the values:
// needs a better name and needs to be moved into a "detail" or "impl" namespace
template< typename T >
using helper = value_wrapper< typename std::decay< T >::type,
std::is_lvalue_reference< T >::value >;
template< typename T >
helper< T > wrap( T&& t )
{
return helper< T >( std::forward< T >( t ) );
}
That way value_wrapper's first template parameter is always the decayed type, which makes everything easier now:
template< typename T, bool BL, bool BR >
bool operator==( const value_wrapper< T, BL >& lhs, const value_wrapper< T, BR >& rhs )
{
return lhs.cref() == rhs.cref();
}
(obviously you want to implement them differently, but you can always access the stored values via cref() in a uniform way)
Live example
You might need to adjust this if you need non-constant access, etc. but I hope the above gets you started. If you need more help/ideas, feel free to ask :)
I admit I had difficulties coming up with a reasonable description for this. I cannot think of a good term that would describe precisely what I'm looking for. Perhaps this could be called a slicing iterator.
Let's say I have something like this:
struct S
{
int i;
char *s;
float f;
};
std::vector<S> v(10);
What I'm looking for is a way to construct an iterator, that would point to a member of S. I'd like to be able to pass it to something like std::min_element without creating a predicate in each case. Something that might look like this:
std::min_element(slicing_iterator(v.begin(), S::f), slicing_iterator(v.end(), S::f));
Is there any template trick that I could use to achieve this? Or perhaps it's already done somewhere in Boost or some other library?
If you're looking for an iterator that converts S into its S::f, this could certainly be done using boost (what can't be?):
std::cout << *std::min_element(
boost::make_transform_iterator(v.begin(), boost::bind(&S::f, _1)),
boost::make_transform_iterator(v.end(), boost::bind(&S::f, _1))
) << '\n';
test: https://ideone.com/jgcHr
But if you're looking for the S whose S::f is the smallest in the vector, the predicate is the most reasonable approach.
If you don't want to create a predicate function for each case, I would suggest not to look for a slicing operator, but to implement your predicate as a lambda function (either using Boost or C++0x). Here you will find a detailed explanation
http://www.codeproject.com/KB/cpp/Sort.aspx
(this is about std::sort, but the comparison in std::min_element works equally.)
Will something like this do the job?
#include <algorithm>
#include <iostream>
#include <vector>
struct S
{
int i;
float f;
S() : i(0), f(0.0f) {}
S(int i_, float f_) : i(i_), f(f_) {}
};
template <typename Iterator, typename T, typename M>
class SlicingIterator : public std::iterator<typename Iterator::iterator_category,M>
{
private:
Iterator m_it;
M T::*m_m;
public:
SlicingIterator(const Iterator& it, M T::*m)
: m_it(it), m_m(m)
{}
const M operator*() const
{
return (*m_it).*m_m;
}
bool operator!=(const SlicingIterator& rhs) const
{
return m_it != rhs.m_it;
}
SlicingIterator& operator++()
{
++m_it;
return *this;
}
bool operator<(const SlicingIterator& rhs) const
{
return m_it < rhs.m_it;
}
};
template <typename Iterator, typename T, typename M>
SlicingIterator<Iterator,T,M> slicing_iterator(const Iterator& it, M T::*m)
{
return SlicingIterator<Iterator,T,M>(it, m);
}
int main()
{
std::vector<S> vec;
vec.push_back(S(23,9));
vec.push_back(S(17,10));
std::copy(slicing_iterator(vec.begin(), &S::f), slicing_iterator(vec.end(), &S::f), std::ostream_iterator<float>(std::cout, " "));
return 0;
}
In addition to what is already suggested you may do it almost exactly like your code sample does.
Example:
template< class IterT, class ObjT, class MemberT >
class slicing_iterator;
template< class IterT, class ObjT, class MemberT >
inline bool operator==(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
template< class IterT, class ObjT, class MemberT >
inline bool operator!=(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
template< class IterT, class ObjT, class MemberT >
class slicing_iterator
{
IterT m_iter;
MemberT ObjT::* m_member;
public:
slicing_iterator( IterT iter, MemberT ObjT::*member ) :
m_iter(iter), m_member(member)
{
}
slicing_iterator& operator++() { ++m_iter; return *this; }
slicing_iterator& operator--() { --m_iter; return *this; }
MemberT& operator*() { return static_cast<ObjT&>(*m_iter).*m_member; }
const MemberT& operator*() const { return static_cast<const ObjT&>(*m_iter).*m_member; }
MemberT* operator->() { return &m_iter->*m_member; }
const MemberT* operator->() const { return &m_iter->*m_member; }
private:
friend bool operator== <IterT,ObjT,MemberT>(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
friend bool operator!= <IterT,ObjT,MemberT>(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
);
};
template< class IterT, class ObjT, class MemberT >
inline bool operator==(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
)
{
return a.m_iter == b.m_iter && a.m_member == a.m_member;
}
template< class IterT, class ObjT, class MemberT >
inline bool operator!=(
const slicing_iterator<IterT,ObjT,MemberT>& a,
const slicing_iterator<IterT,ObjT,MemberT>& b
)
{
return a.m_iter != b.m_iter || a.m_member != a.m_member;
}
template< class IterT, class ObjT, class MemberT >
inline slicing_iterator<IterT,ObjT,MemberT>
make_slicing_iterator( IterT iter, MemberT ObjT::*member )
{
return slicing_iterator<IterT,ObjT,MemberT>( iter, member );
}
struct S
{
int i;
char *s;
float f;
};
int main(void)
{
std::vector<S> v(10);
std::min_element(
make_slicing_iterator(v.begin(), &S::f),
make_slicing_iterator(v.end(), &S::f)
);
return 0;
}
At first I didn't notice - it looks similar to what #Stuart Golodetz suggested but the advantage is that operator< doesn't have to be defined for iterator type (e.g. std::list::iterator). It makes this implementation universal.
template <class T>
class A
{
private:
T m_var;
public:
operator T () const { return m_var; }
........
}
template<class T, class U, class V>
const A<T> operator+ (const U& r_var1, const V& r_var2)
{ return A<T> ( (T)r_var1 + (T)r_var2 ); }
The idea is to overload the + operator once (instead of three) for the cases:
number + A, A + number, A + A (where number is of type T, the same as m_var).
An interesting case would be if m_var is e.g. int and r_var is long.
Any helps would be highly appreciated. Thank you.
The common pattern to achieve what you want is to actually perform it in the opposite direction: provide an implicit conversion from T to the template and only define the operator for the template.
template <typename T>
struct test {
T m_var;
test( T const & t ) : m_var(t) {} // implicit conversion
test& operator+=( T const & rhs ) {
m_var += rhs.m_var;
}
friend test operator+( test lhs, test const & rhs ) { // *
return lhs += rhs;
}
};
// * friend only to allow us to define it inside the class declaration
A couple of details on the idiom: operator+ is declared as friend only to allow us to define a free function inside the class curly braces. This has some advantages when it comes to lookup for the compiler, as it will only consider that operator if either one of the arguments is already a test.
Since the constructor is implicit, a call test<int> a(0); test<int> b = a + 5; will be converted into the equivalent of test<int> b( a + test<int>(5) ); Conversely if you switch to 5 + a.
The operator+ is implemented in terms of operator+=, in a one-liner by taking the first argument by value. If the operator was any more complex this would have the advantage of providing both operators with a single implementation.
The issue with your operator+ is you have 3 template parameters, one for the return type as well as the cast, but there is no way for the compiler to automatically resolve that parameter.
You are also committing a few evils there with casts.
You can take advantage of the that if you define operator+ as a free template function in your namespace it will only have effect for types defined in that namespace.
Within your namespace therefore I will define, using just T and U
template< typename T >
T operator+( const T & t1, const T& t2 )
{
T t( t1 );
t += t2; // defined within T in your namespace
return t;
}
template< typename T, typename U >
T operator+( const T& t, const U& u )
{
return t + T(u);
}
template< typename T, typename U >
T operator+( const U& u, const T& t )
{
return T(u) + t;
}
a + b in general is not covered by this template unless one of the types of a and b is in the namespace where the template was defined.
You should not overload op+ for unrelated types that you know nothing about – this can break perfectly working code that already exists. You should involve your class as at least one of the parameters to the op+ overload.
If you don't want an implicit conversion from T to A<T>, then I would just write out the overloads. This is the clearest code, and isn't long at all, if you follow the "# to #=" overloading pattern:
template<class T>
struct A {
explicit A(T);
A& operator+=(A const &other) {
m_var += other.m_var;
// This could be much longer, but however long it is doesn't change
// the length of the below overloads.
return *this;
}
A& operator+=(T const &other) {
*this += A(other);
return *this;
}
friend A operator+(A a, A const &b) {
a += b;
return a;
}
friend A operator+(A a, T const &b) {
a += A(b);
return a;
}
friend A operator+(T const &a, A b) {
b += A(a);
return b;
}
private:
T m_var;
};
C++0x solution
template <class T>
class A
{
private:
T m_var;
public:
operator T () const { return m_var; }
A(T x): m_var(x){}
};
template<class T,class U, class V>
auto operator+ (const U& r_var1, const V& r_var2) -> decltype(r_var1+r_var2)
{
return (r_var1 + r_var2 );
}
int main(){
A<int> a(5);
a = a+10;
a = 10 + a;
}
Unfortunately changing template<class T,class U, class V> to template<class U, class V> invokes segmentation fault on gcc 4.5.1. I have no idea why?