views:

325

answers:

3

From wikipedia:

// A class template to express an equality comparison interface.
template<typename T> class equal_comparable
{
    friend bool operator==(T const &a, T const &b) { return  a.equal_to(b); }
    friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); }
};

class value_type
// Class value_type wants to have == and !=, so it derives from
// equal_comparable with itself as argument (which is the CRTP).
     : private equal_comparable<value_type>
{
public:
    bool equal_to(value_type const& rhs) const; // to be defined
};

This is supposed to be the Barton-Nackman, that could achieve compile-time dimensional analysis (checking if some operations applied to variables end up in comparable numbers, like speed comparable to space/time but no acceleration).

Could anyone explain me how, or at least explain me what are the NON-TEMPLATE members?

Thanks

A: 

These are actually nontemplate nonmembers - the comparison operators in the base template - they get used by the ADL for the derived class. A template member would be something like:


class C
{
    ...
    template < typename T > void DoGreatStuff( T t ) { ... }
    ...
};
Nikolai N Fetissov
A: 

The instantiation of equal_comparable<value_type> in value_type class causes the compiler to generate two comparison functions:

friend bool operator==(value_type const &a, value_type const &b) { return  a.equal_to(b); }
friend bool operator!=(value_type const &a, value_type const &b) { return !a.equal_to(b); }

These functions are nontemplate since they do not depend on any template parameter, but they are also nonmembers since they are declared as friend.

Bojan Resnik
+1  A: 

The rules of the language have changed since the pattern was invented, although care was taken not to break it. In other words, as far as I can tell, it still works but for different reasons than it originally did. I don't think I would base an attempt at dimensional analysis on this pattern as I think there are better ways of doing that today.

I also think the example is too trivial to be helpful. As already stated the instantiation of equal_comparable<value_type> causes operator== and operator!= for value_type to appear. Since they are non-members it doesn't matter that the inheritance is private, they're still eligable for selection when resolving a call. It's just hard to see the point in this example. Let's say however, that you add a template parameter to equal_comparable and a few other things:

template<typename U, typename V> class equal_comparable
{
    friend bool operator==(U const &a, V const &b) { return  a.equal_to(b); }
    friend bool operator!=(U const &a, V const &b) { return !a.equal_to(b); }
};

class some_other_type 
{
    bool equal_to(value_type const& rhs) const;
};

class value_type
: private equal_comparable<value_type>,      // value_type comparable to itself
  private equal_comparable<some_other_type>  // value_type comparable to some_other_type
{
public:
    bool equal_to(value_type const& rhs) const;
    bool equal_to(some_other_type const& rhs) const;
};

Disclaimer: I have no idea if this is the way it's supposed to be used but I'm reasonably sure that it would work as described.

j2
Thanks, this helps me to understand it.
alvatar