Comparison with no explicit member template arguments and no template template parameter

struct WrappedLess
{
    template<class T> struct Impl
    {
        typedef std::less<T> type;
    };
};
template<class ValueCmp = WrappedLess> class CompareRecord
{
public:
    CompareRecord():resultKnown_(false),everyThingTested_(false),result_(false){};
    // was useful for printing base classes - and may be useful for
    // other binary traversions - only here it cannot do something
    // meaningful.
    template<class ReflectedClass> void 
    operator()(const ReflectedClass&, const ReflectedClass&)  
    {/* no op*/}

    // here ValueType is neither compiletime- nor runtime iterable.
    // Hence it can be compared "as is" or the user has to define an 
    // operator<(const ValueType& lhs, const ValueType& rhs)
    template<class WrappedScope, class NameTag, class ValueType> 
    void operator()(const ValueType& lhsValue,const ValueType& rhsValue,
                    NameTag,WrappedScope, WrappedScope)
    {
        typedef typename ValueCmp::template Impl<ValueType>::type Comparison;
        if(!resultKnown_)
        {
            Comparison cmp;
            result_ = cmp(lhsValue, rhsValue);
            resultKnown_ = result_ ||               // lhs precedes rhs 
                            cmp(rhsValue,lhsValue); // rhs precedes lhs 
        }
    }
private:
    template<class WrappedScope, class NameTag, class ValueType> 
    void missingPartialOrdering(const ValueType&,const ValueType&,
                    NameTag,WrappedScope, WrappedScope,LeaveAttributeTag)
    {
        typedef typename WrappedScope::type Scope;
        enum {lastAttribute = Scope::AttributePos<NameTag,Scope::ThisClass>::value == Scope::NumAttributes - 1};
        // in a nested structure of reflected classes this may be true when
        // in the outermost class still attributes are to check.
        // This is no problem as long as no attempt is made to treat the comparison 
        // result at that stage as a comparison result for the outermost class.
        everyThingTested_ = lastAttribute;
    };        
    template<class WrappedScope, class NameTag, class ValueType> 
    void missingPartialOrdering(const ValueType&,const ValueType&,
                    NameTag,WrappedScope, WrappedScope,int /* not leaving an attribute*/)
    {/* no op*/}
public:
    template<class WrappedScope, class NameTag, class ValueType, class GraphEvent> 
    void operator()(const ValueType& lhsValue,const ValueType& rhsValue,NameTag attributeTag,
                    GraphEvent,WrappedScope lhsScope, WrappedScope rhsScope)
    {
        enum {leaveAttribute = boost::is_same<GraphEvent,
                                        LeaveAttributeTag>::value};
        typedef typename boost::ct_if<(leaveAttribute == 0),
                            int,
                            LeaveAttributeTag>::type
            type;
        missingPartialOrdering(lhsValue, rhsValue, attributeTag, lhsScope, rhsScope, type());
    }
    // lhs collection ran out of bullets
    template<class WrappedScope, class NameTag, class ValueIter> 
    void operator()(PastEndTag,ValueIter /* rhsPos */,ValueIter /* rhsEnd */,
                    NameTag,WrappedScope, WrappedScope)
    {
        if(!resultKnown_)
        {
            // lexicographical sort: "a" < "aa"
            result_ = true;
            resultKnown_ = true;
        }
    }
    // rhs collection ran out of bullets
    template<class WrappedScope, class NameTag, class ValueIter> 
    void operator()(ValueIter/* lhsPos */,ValueIter /* lhsEnd */, PastEndTag,
                    NameTag,WrappedScope, WrappedScope)
    {
        if(!resultKnown_)
        {
            // lexicographical sort: "a" < "aa"
            result_ = false;
            resultKnown_ = true;
        }
    }
    // lhs is a null pointer and rhs was not - hence it could be dereferenced
    template<class WrappedScope, class NameTag, class ValueType> 
    void operator()(PastEndTag,const ValueType& /*rhsValue*/,
                    NameTag,WrappedScope, WrappedScope)
    {
        if(!resultKnown_)
        {
            // lexicographical sort: "a" < "aa"
            result_ = true;
            resultKnown_ = true;
        }
    }
    // rhs is a null pointer and lhs was not - hence it could be dereferenced
    template<class WrappedScope, class NameTag, class ValueType> 
    void operator()(const ValueType& /*lhsValue*/,PastEndTag,
                    NameTag,WrappedScope, WrappedScope)
    {
        if(!resultKnown_)
        {
            // lexicographical sort: "a" < "aa"
            result_ = false;
            resultKnown_ = true;
        }
    }
    bool result()
    {
        if(!resultKnown_ && !everyThingTested_)
            throw std::logic_error("trying to access an undefined comparison result");
        return result_;
    }
    // a nested DoneTag type is needed to be able to detect conditional traversion end
    // with MSVC6 (sorry for that).
    // (once the traversion has reached attributes with non-equivalent values (with
    // respect to the comparison ValueCmp::Impl<T>::type) you might want to end
    // the traversion)
    typedef int DoneTag;
    bool done()const
    {
        return resultKnown_;
    }
private:
    bool everyThingTested_;
    bool result_;
    bool resultKnown_;
};

template<class Record> inline bool recordIsLess(const Record& lhs, 
                                            const Record& rhs)
{
    CompareRecord<> comparison;
    depthFirstForeachIncAllBaseClasses(lhs, rhs, comparison, InstanceVariableTag()); 
    return comparison.result();
};

Last revised: September 13, 2004 Copyright © 2004 Arne Adams