Member/nonmember operator template partial ordering
Section [temp.func.order]
Nathan Sidwell

Created on 2005-09-16.00:00:00 last changed 96 months ago


Date: 2010-08-15.00:00:00

[Voted into WP at August, 2010 meeting.]

Date: 2010-02-15.00:00:00

Proposed resolution (February, 2010):

Change [temp.func.order] paragraph 3 as follows:

...and substitute it for each occurrence of that parameter in the function type of the template. If only one of the function templates is a non-static member, that function template is considered to have a new first parameter inserted in its function parameter list. The new parameter is of type “reference to cv A,” where cv are the cv-qualifiers of the function template (if any) and A is the class of which the function template is a member. [Note: This allows a non-static member to be ordered with respect to a nonmember function and for the results to be equivalent to the ordering of two equivalent nonmembers. —end note] [Example:

  struct A { };
  template<class T> struct B {
    template<typename R> int operator*(R&); // #1

  template<typename T, typename R> int operator*(T&, R&); // #2

  // The declaration of B::operator* is transformed into the equivalent of
  // template<typename R> int operator*(B<A>&, R&);  // #1a

  int main() {
    A a;
    B<A> b;
    b * a;   // calls #1a

end example]

Date: 2006-04-15.00:00:00

Notes from the April, 2006 meeting:

The group favored option 2.

Date: 2005-09-16.00:00:00

The Standard does not specify how member and nonmember function templates are to be ordered. This question arises with an example like the following:

    struct A {
        template<class T> void operator<<(T&);

    template<class T> struct B { };
    template<class T> void operator<<(A&, B<T>&);

    int main() {
        A a;
        B<A> b;
        a << b;

The two candidates for “a << b” are:

  1. A::operator<< <B<A> >(B<A>&)
  2. ::operator<< <A>(A&, B<A>&)

How should we treat the implicit this parameter of #1 and the explicit first parameter of #2?

    Option 0: Make them unordered.

    Option 1: If either function is a non-static member function, ignore any this parameter and ignore the first parameter of any non-member function. This option will select #2, as “B<T>&” is more specialized than “T&”.

    Option 2: Treat the this parameter as if it were of reference to object type, and then perform comparison to the first parameter of the other function. The other function's first parameter will either be another this parameter, or it will be a by-value or by-reference object parameter. In the example above, this option will also select #2.

The difference between option 1 and option 2 can be seen in the following example:

    struct A { };

    template<class T> struct B {
        template<typename R> int operator*(R&);   // #1

    template <typename T> int operator*(T&, A&);  // #2

    int main() {
        A a;
        B<A> b;
        b * a;

Should this select #1, select #2, or be ambiguous? Option 1 will select #2, because “A&” is more specialized than “T&”. Option 2 will make this example ambiguous, because “B<A>&” is more specialized than “T&”.

If one were considering two non-member templates,

    template <typename T> int operator*(T&, A&);                 // #2
    template <typename T, typename R> int operator*(B<A>&, R&);  // #3

the current rules would make these unordered. Option 2 thus seems more consistent with this existing behavior.

Date User Action Args
2014-03-03 00:00:00adminsetstatus: fdis -> c++11
2011-04-10 00:00:00adminsetstatus: wp -> fdis
2010-11-29 00:00:00adminsetstatus: dr -> wp
2010-08-23 00:00:00adminsetmessages: + msg2924
2010-08-23 00:00:00adminsetstatus: review -> dr
2010-02-16 00:00:00adminsetmessages: + msg2557
2010-02-16 00:00:00adminsetstatus: drafting -> review
2006-04-22 00:00:00adminsetmessages: + msg1335
2006-04-22 00:00:00adminsetstatus: open -> drafting
2005-09-16 00:00:00admincreate