#include <tuple>
template<class T, class Func, class BaseList> struct require_all_bases_type;
template<class T, class Func, class...Bases>
struct require_all_bases_type<T, Func,std::tuple<Bases...>>
{
require_all_bases_type(Func f=Func{}) :f(std::move(f)) {}
//binary operator
bool operator()(const T& left, const T& right)
{return execute<Bases...>(left, right, std::integral_constant<bool,(sizeof...(Bases)>1)>{});}
//unary operator
bool operator()(const T& left)
{return execute<Bases...>(left);}
private:
//binary expander
template<class CurBase, class...Rest> bool execute(const T& left, const T& right, std::true_type)
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right)) && execute<Rest...>(left, right, std::integral_constant<bool,(sizeof...(Rest)>1)>{});}
//binary end-case
template<class CurBase> bool execute(const T& left, const T& right, std::false_type)
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right));}
//unary expander
template<class CurBase, class...Rest> bool execute(const T& left, std::true_type)
{return f(static_cast<const CurBase&>(left)) && execute<Rest...>(left, std::integral_constant<bool,(sizeof...(Rest)>1)>{});}
//unary end-case
template<class CurBase> bool execute(const T& left, std::false_type)
{return f(static_cast<const CurBase&>(left));}
Func f;
};
template<class BaseList, class T, class Func>
bool require_all_bases(const T& left, const T& right, Func f={})
{return require_all_bases_type<T,Func,BaseList>(std::move(f))(left, right);}
template<class T, class Func, class BaseList> struct compare_bases_type;
template<class T, class Func, class...Bases>
struct compare_bases_type<T, Func, std::tuple<Bases...>>
{
compare_bases_type(Func f=Func{}) :f(std::move(f)) {}
bool operator()(const T& left, const T& right)
{return execute<Bases...>(left, right, std::integral_constant<bool,(sizeof...(Bases)>1)>{});}
private:
template<class CurBase, class...Rest>
bool execute(const T& left, const T& right, std::true_type)
{
const CurBase& l = left;
const CurBase& r = right;
if (!(l==r))
return f(l,r);
return execute<Rest...>(left, right, std::integral_constant<bool,(sizeof...(Rest)>1)>{});
}
template<class CurBase> bool execute(const T& left, const T& right, std::false_type)
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right));}
Func f;
};
template<class BaseList, class T, class Func>
bool compare_bases(const T& left, const T& right, Func f={})
{return compare_bases_type<T,Func,BaseList>(std::move(f))(left, right);}
#include <cstdlib>
#include <iostream>
#include <functional>
//////////////////////////////////////////////////////////////////////////////////
struct Base1
{
Base1( unsigned& val ) : m_val( val ){}
bool operator==( const Base1& rhs )const { return m_val == rhs.m_val; }
unsigned& m_val;
};
//////////////////////////////////////////////////////////////////////////////////
struct Base2
{
Base2( unsigned& val ) : m_val( val ){}
bool operator==( const Base2& rhs ) const { return m_val == rhs.m_val; }
unsigned& m_val;
};
//////////////////////////////////////////////////////////////////////////////////
class Derived : public Base1 , public Base2 // Real problem has many more more Base classes
{
typedef std::tuple<Base1,Base2> BaseList;
public:
Derived( unsigned& val1 , unsigned& val2 ) : Base1( val1 ) , Base2( val2 )
{
}
bool operator==( const Derived& rhs ) const
{return require_all_bases<BaseList>(*this,rhs,std::equal_to<void>{});}
//bool operator!=( const Derived& rhs ) const
//{return require_all_bases<BaseList>(*this,rhs,std::not_equal_to<void>{});}
//bool operator<( const Derived& rhs ) const
//{return compare_bases<BaseList>(*this,rhs,std::less<void>{});}
//bool operator<=( const Derived& rhs ) const
//{return compare_bases<BaseList>(*this,rhs,std::less_equal<void>{});}
//bool operator>=( const Derived& rhs ) const
//{return compare_bases<BaseList>(*this,rhs,std::greater_equal<void>{});}
//bool operator>( const Derived& rhs ) const
//{return compare_bases<BaseList>(*this,rhs,std::greater<void>{});}
};
//////////////////////////////////////////////////////////////////////////////////
int main()
{
unsigned val1 = 42 , val2 = 24 , val3 = 0;
Derived d1( val1 , val2 );
Derived d2( val1 , val3 );
std::cout << ( d1 == d2 ) << std::endl;
return EXIT_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////////////
I2luY2x1ZGUgPHR1cGxlPgoKdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MgRnVuYywgY2xhc3MgQmFzZUxpc3Q+IHN0cnVjdCByZXF1aXJlX2FsbF9iYXNlc190eXBlOwp0ZW1wbGF0ZTxjbGFzcyBULCBjbGFzcyBGdW5jLCBjbGFzcy4uLkJhc2VzPgpzdHJ1Y3QgcmVxdWlyZV9hbGxfYmFzZXNfdHlwZTxULCBGdW5jLHN0ZDo6dHVwbGU8QmFzZXMuLi4+Pgp7CglyZXF1aXJlX2FsbF9iYXNlc190eXBlKEZ1bmMgZj1GdW5je30pIDpmKHN0ZDo6bW92ZShmKSkge30KCQoJLy9iaW5hcnkgb3BlcmF0b3IKCWJvb2wgb3BlcmF0b3IoKShjb25zdCBUJiBsZWZ0LCBjb25zdCBUJiByaWdodCkKICAgIHtyZXR1cm4gZXhlY3V0ZTxCYXNlcy4uLj4obGVmdCwgcmlnaHQsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8Ym9vbCwoc2l6ZW9mLi4uKEJhc2VzKT4xKT57fSk7fQoJLy91bmFyeSBvcGVyYXRvcgoJYm9vbCBvcGVyYXRvcigpKGNvbnN0IFQmIGxlZnQpCgl7cmV0dXJuIGV4ZWN1dGU8QmFzZXMuLi4+KGxlZnQpO30KcHJpdmF0ZToKCS8vYmluYXJ5IGV4cGFuZGVyCgl0ZW1wbGF0ZTxjbGFzcyBDdXJCYXNlLCBjbGFzcy4uLlJlc3Q+IGJvb2wgZXhlY3V0ZShjb25zdCBUJiBsZWZ0LCBjb25zdCBUJiByaWdodCwgc3RkOjp0cnVlX3R5cGUpCgl7cmV0dXJuIGYoc3RhdGljX2Nhc3Q8Y29uc3QgQ3VyQmFzZSY+KGxlZnQpLHN0YXRpY19jYXN0PGNvbnN0IEN1ckJhc2UmPihyaWdodCkpICYmIGV4ZWN1dGU8UmVzdC4uLj4obGVmdCwgcmlnaHQsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8Ym9vbCwoc2l6ZW9mLi4uKFJlc3QpPjEpPnt9KTt9CgkvL2JpbmFyeSBlbmQtY2FzZQoJdGVtcGxhdGU8Y2xhc3MgQ3VyQmFzZT4gYm9vbCBleGVjdXRlKGNvbnN0IFQmIGxlZnQsIGNvbnN0IFQmIHJpZ2h0LCBzdGQ6OmZhbHNlX3R5cGUpCgl7cmV0dXJuIGYoc3RhdGljX2Nhc3Q8Y29uc3QgQ3VyQmFzZSY+KGxlZnQpLHN0YXRpY19jYXN0PGNvbnN0IEN1ckJhc2UmPihyaWdodCkpO30KCS8vdW5hcnkgZXhwYW5kZXIKCXRlbXBsYXRlPGNsYXNzIEN1ckJhc2UsIGNsYXNzLi4uUmVzdD4gYm9vbCBleGVjdXRlKGNvbnN0IFQmIGxlZnQsIHN0ZDo6dHJ1ZV90eXBlKQoJe3JldHVybiBmKHN0YXRpY19jYXN0PGNvbnN0IEN1ckJhc2UmPihsZWZ0KSkgJiYgZXhlY3V0ZTxSZXN0Li4uPihsZWZ0LCBzdGQ6OmludGVncmFsX2NvbnN0YW50PGJvb2wsKHNpemVvZi4uLihSZXN0KT4xKT57fSk7fQoJLy91bmFyeSBlbmQtY2FzZQoJdGVtcGxhdGU8Y2xhc3MgQ3VyQmFzZT4gYm9vbCBleGVjdXRlKGNvbnN0IFQmIGxlZnQsIHN0ZDo6ZmFsc2VfdHlwZSkKCXtyZXR1cm4gZihzdGF0aWNfY2FzdDxjb25zdCBDdXJCYXNlJj4obGVmdCkpO30KCQoJRnVuYyBmOwp9Owp0ZW1wbGF0ZTxjbGFzcyBCYXNlTGlzdCwgY2xhc3MgVCwgY2xhc3MgRnVuYz4gCmJvb2wgcmVxdWlyZV9hbGxfYmFzZXMoY29uc3QgVCYgbGVmdCwgY29uc3QgVCYgcmlnaHQsIEZ1bmMgZj17fSkKe3JldHVybiByZXF1aXJlX2FsbF9iYXNlc190eXBlPFQsRnVuYyxCYXNlTGlzdD4oc3RkOjptb3ZlKGYpKShsZWZ0LCByaWdodCk7fQoKdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MgRnVuYywgY2xhc3MgQmFzZUxpc3Q+IHN0cnVjdCBjb21wYXJlX2Jhc2VzX3R5cGU7CnRlbXBsYXRlPGNsYXNzIFQsIGNsYXNzIEZ1bmMsIGNsYXNzLi4uQmFzZXM+CnN0cnVjdCBjb21wYXJlX2Jhc2VzX3R5cGU8VCwgRnVuYywgc3RkOjp0dXBsZTxCYXNlcy4uLj4+CnsKCWNvbXBhcmVfYmFzZXNfdHlwZShGdW5jIGY9RnVuY3t9KSA6ZihzdGQ6Om1vdmUoZikpIHt9CgkKCWJvb2wgb3BlcmF0b3IoKShjb25zdCBUJiBsZWZ0LCBjb25zdCBUJiByaWdodCkKCXtyZXR1cm4gZXhlY3V0ZTxCYXNlcy4uLj4obGVmdCwgcmlnaHQsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8Ym9vbCwoc2l6ZW9mLi4uKEJhc2VzKT4xKT57fSk7fQpwcml2YXRlOgoJdGVtcGxhdGU8Y2xhc3MgQ3VyQmFzZSwgY2xhc3MuLi5SZXN0PgoJYm9vbCBleGVjdXRlKGNvbnN0IFQmIGxlZnQsIGNvbnN0IFQmIHJpZ2h0LCBzdGQ6OnRydWVfdHlwZSkKCXsKCQljb25zdCBDdXJCYXNlJiBsID0gbGVmdDsKCQljb25zdCBDdXJCYXNlJiByID0gcmlnaHQ7CgkJaWYgKCEobD09cikpIAoJCQlyZXR1cm4gZihsLHIpOwoJCXJldHVybiBleGVjdXRlPFJlc3QuLi4+KGxlZnQsIHJpZ2h0LCBzdGQ6OmludGVncmFsX2NvbnN0YW50PGJvb2wsKHNpemVvZi4uLihSZXN0KT4xKT57fSk7Cgl9Cgl0ZW1wbGF0ZTxjbGFzcyBDdXJCYXNlPiBib29sIGV4ZWN1dGUoY29uc3QgVCYgbGVmdCwgY29uc3QgVCYgcmlnaHQsIHN0ZDo6ZmFsc2VfdHlwZSkKCXtyZXR1cm4gZihzdGF0aWNfY2FzdDxjb25zdCBDdXJCYXNlJj4obGVmdCksc3RhdGljX2Nhc3Q8Y29uc3QgQ3VyQmFzZSY+KHJpZ2h0KSk7fQoJCglGdW5jIGY7Cn07CnRlbXBsYXRlPGNsYXNzIEJhc2VMaXN0LCBjbGFzcyBULCBjbGFzcyBGdW5jPiAKYm9vbCBjb21wYXJlX2Jhc2VzKGNvbnN0IFQmIGxlZnQsIGNvbnN0IFQmIHJpZ2h0LCBGdW5jIGY9e30pCntyZXR1cm4gY29tcGFyZV9iYXNlc190eXBlPFQsRnVuYyxCYXNlTGlzdD4oc3RkOjptb3ZlKGYpKShsZWZ0LCByaWdodCk7fQoKCgoKI2luY2x1ZGUgPGNzdGRsaWI+CiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPGZ1bmN0aW9uYWw+CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpzdHJ1Y3QgQmFzZTEKewoJQmFzZTEoIHVuc2lnbmVkJiB2YWwgKSA6IG1fdmFsKCB2YWwgKXt9Cglib29sIG9wZXJhdG9yPT0oIGNvbnN0IEJhc2UxJiByaHMgKWNvbnN0IHsgcmV0dXJuIG1fdmFsID09IHJocy5tX3ZhbDsgfQoJdW5zaWduZWQmIG1fdmFsOwp9OwoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKc3RydWN0IEJhc2UyCnsKCUJhc2UyKCB1bnNpZ25lZCYgdmFsICkgOiBtX3ZhbCggdmFsICl7fQoJYm9vbCBvcGVyYXRvcj09KCBjb25zdCBCYXNlMiYgcmhzICkgY29uc3QgeyByZXR1cm4gbV92YWwgPT0gcmhzLm1fdmFsOyB9Cgl1bnNpZ25lZCYgbV92YWw7Cn07CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpjbGFzcyBEZXJpdmVkIDogcHVibGljIEJhc2UxICwgcHVibGljIEJhc2UyCQkvLyBSZWFsIHByb2JsZW0gaGFzIG1hbnkgbW9yZSBtb3JlIEJhc2UgY2xhc3Nlcwp7Cgl0eXBlZGVmIHN0ZDo6dHVwbGU8QmFzZTEsQmFzZTI+IEJhc2VMaXN0OwpwdWJsaWM6CglEZXJpdmVkKCB1bnNpZ25lZCYgdmFsMSAsIHVuc2lnbmVkJiB2YWwyICkgOiBCYXNlMSggdmFsMSApICwgQmFzZTIoIHZhbDIgKQoJewoJfQoJCglib29sIG9wZXJhdG9yPT0oIGNvbnN0IERlcml2ZWQmIHJocyApIGNvbnN0Cgl7cmV0dXJuIHJlcXVpcmVfYWxsX2Jhc2VzPEJhc2VMaXN0PigqdGhpcyxyaHMsc3RkOjplcXVhbF90bzx2b2lkPnt9KTt9CgkvL2Jvb2wgb3BlcmF0b3IhPSggY29uc3QgRGVyaXZlZCYgcmhzICkgY29uc3QKCS8ve3JldHVybiByZXF1aXJlX2FsbF9iYXNlczxCYXNlTGlzdD4oKnRoaXMscmhzLHN0ZDo6bm90X2VxdWFsX3RvPHZvaWQ+e30pO30KCS8vYm9vbCBvcGVyYXRvcjwoIGNvbnN0IERlcml2ZWQmIHJocyApIGNvbnN0CgkvL3tyZXR1cm4gY29tcGFyZV9iYXNlczxCYXNlTGlzdD4oKnRoaXMscmhzLHN0ZDo6bGVzczx2b2lkPnt9KTt9CgkvL2Jvb2wgb3BlcmF0b3I8PSggY29uc3QgRGVyaXZlZCYgcmhzICkgY29uc3QKCS8ve3JldHVybiBjb21wYXJlX2Jhc2VzPEJhc2VMaXN0PigqdGhpcyxyaHMsc3RkOjpsZXNzX2VxdWFsPHZvaWQ+e30pO30KCS8vYm9vbCBvcGVyYXRvcj49KCBjb25zdCBEZXJpdmVkJiByaHMgKSBjb25zdAoJLy97cmV0dXJuIGNvbXBhcmVfYmFzZXM8QmFzZUxpc3Q+KCp0aGlzLHJocyxzdGQ6OmdyZWF0ZXJfZXF1YWw8dm9pZD57fSk7fQoJLy9ib29sIG9wZXJhdG9yPiggY29uc3QgRGVyaXZlZCYgcmhzICkgY29uc3QKCS8ve3JldHVybiBjb21wYXJlX2Jhc2VzPEJhc2VMaXN0PigqdGhpcyxyaHMsc3RkOjpncmVhdGVyPHZvaWQ+e30pO30KfTsKCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmludCBtYWluKCkKewoJdW5zaWduZWQgdmFsMSA9IDQyICwgdmFsMiA9IDI0ICwgdmFsMyA9IDA7CglEZXJpdmVkIGQxKCB2YWwxICwgdmFsMiApOwoJRGVyaXZlZCBkMiggdmFsMSAsIHZhbDMgKTsKCglzdGQ6OmNvdXQgPDwgKCBkMSA9PSBkMiApIDw8IHN0ZDo6ZW5kbDsKCXJldHVybiBFWElUX1NVQ0NFU1M7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8=
In file included from /usr/include/c++/4.8/string:48:0,
from /usr/include/c++/4.8/stdexcept:39,
from /usr/include/c++/4.8/array:38,
from /usr/include/c++/4.8/tuple:39,
from prog.cpp:1:
/usr/include/c++/4.8/bits/stl_function.h: In instantiation of ‘struct std::equal_to<void>’:
prog.cpp:98:68: required from here
/usr/include/c++/4.8/bits/stl_function.h:207:7: error: forming reference to void
operator()(const _Tp& __x, const _Tp& __y) const
^
prog.cpp: In instantiation of ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::execute(const T&, const T&, std::true_type) [with CurBase = Base1; Rest = {Base2}; T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}; std::true_type = std::integral_constant<bool, true>]’:
prog.cpp:11:20: required from ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::operator()(const T&, const T&) [with T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}]’
prog.cpp:33:74: required from ‘bool require_all_bases(const T&, const T&, Func) [with BaseList = std::tuple<Base1, Base2>; T = Derived; Func = std::equal_to<void>]’
prog.cpp:98:69: required from here
prog.cpp:18:82: error: no match for call to ‘(std::equal_to<void>) (const Base1&, const Base1&)’
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right)) && execute<Rest...>(left, right, std::integral_constant<bool,(sizeof...(Rest)>1)>{});}
^
prog.cpp: In instantiation of ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::execute(const T&, const T&, std::false_type) [with CurBase = Base2; T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}; std::false_type = std::integral_constant<bool, false>]’:
prog.cpp:18:92: required from ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::execute(const T&, const T&, std::true_type) [with CurBase = Base1; Rest = {Base2}; T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}; std::true_type = std::integral_constant<bool, true>]’
prog.cpp:11:20: required from ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::operator()(const T&, const T&) [with T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}]’
prog.cpp:33:74: required from ‘bool require_all_bases(const T&, const T&, Func) [with BaseList = std::tuple<Base1, Base2>; T = Derived; Func = std::equal_to<void>]’
prog.cpp:98:69: required from here
prog.cpp:21:80: error: no match for call to ‘(std::equal_to<void>) (const Base2&, const Base2&)’
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right));}
^
prog.cpp: In member function ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::execute(const T&, const T&, std::true_type) [with CurBase = Base1; Rest = {Base2}; T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}; std::true_type = std::integral_constant<bool, true>]’:
prog.cpp:18:167: warning: control reaches end of non-void function [-Wreturn-type]
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right)) && execute<Rest...>(left, right, std::integral_constant<bool,(sizeof...(Rest)>1)>{});}
^
prog.cpp: In member function ‘bool require_all_bases_type<T, Func, std::tuple<_Tail ...> >::execute(const T&, const T&, std::false_type) [with CurBase = Base2; T = Derived; Func = std::equal_to<void>; Bases = {Base1, Base2}; std::false_type = std::integral_constant<bool, false>]’:
prog.cpp:21:82: warning: control reaches end of non-void function [-Wreturn-type]
{return f(static_cast<const CurBase&>(left),static_cast<const CurBase&>(right));}
^