<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><span class="vcard"><a class="email" href="mailto:tobi@die-loews.de" title="Tobias Loew <tobi@die-loews.de>"> <span class="fn">Tobias Loew</span></a>
</span> changed
          <a class="bz_bug_link 
          bz_status_REOPENED "
   title="REOPENED - user-defined template operator < not used"
   href="https://bugs.llvm.org/show_bug.cgi?id=48611">bug 48611</a>
          <br>
             <table border="1" cellspacing="0" cellpadding="8">
          <tr>
            <th>What</th>
            <th>Removed</th>
            <th>Added</th>
          </tr>

         <tr>
           <td style="text-align:right;">Resolution</td>
           <td>INVALID
           </td>
           <td>---
           </td>
         </tr>

         <tr>
           <td style="text-align:right;">Status</td>
           <td>RESOLVED
           </td>
           <td>REOPENED
           </td>
         </tr></table>
      <p>
        <div>
            <b><a class="bz_bug_link 
          bz_status_REOPENED "
   title="REOPENED - user-defined template operator < not used"
   href="https://bugs.llvm.org/show_bug.cgi?id=48611#c5">Comment # 5</a>
              on <a class="bz_bug_link 
          bz_status_REOPENED "
   title="REOPENED - user-defined template operator < not used"
   href="https://bugs.llvm.org/show_bug.cgi?id=48611">bug 48611</a>
              from <span class="vcard"><a class="email" href="mailto:tobi@die-loews.de" title="Tobias Loew <tobi@die-loews.de>"> <span class="fn">Tobias Loew</span></a>
</span></b>
        <pre>Hi David,

this bug is not about overload-resolution between functions and
template-functions. Below is a shorter example with only one enum:

First, a quote from the standard [over.built] 1.:

/*********************************************

The candidate operator functions that represent the built-in operators defined
in [expr.compound] are specified in this subclause. These candidate functions
participate in the operator overload resolution process as described in
[over.match.oper] and are used for no other purpose.
[Note 1: Because built-in operators take only operands with non-class type, and
operator overload resolution occurs only when an operand expression originally
has class or enumeration type, operator overload resolution can resolve to a
built-in operator only when an operand has a class type that has a user-defined
conversion to a non-class type appropriate for the operator, or when an operand
has an enumeration type that can be converted to a type appropriate for the
operator. Also note that some of the candidate operator functions given in this
subclause are more permissive than the built-in operators themselves. As
described in [over.match.oper], after a built-in operator is selected by
overload resolution the expression is subject to the requirements for the
built-in operator given in [expr.compound], and therefore to any additional
semantic constraints given there. If there is a user-written candidate with the
same name and parameter types as a built-in candidate operator function, the
built-in operator function is hidden and is not included in the set of
candidate functions. — end note]

*****************************************/

The last sentence of Note 1 states, that built-in operators are hidden when a
candidate with the same name and parameter types exists



/******************************************************

#include <iostream>

enum E2 {
    e2_a
};

template<class E>
inline bool operator<(E, E) {                                  // (1)
    return true;
}


int main()
{
    if (E2::e2_a < E2::e2_a) {                                 // (2)
        std::cout << "user-defined operator used for E2\n";
    } else {
        std::cout << "builtin operator used for E2\n";
    }
}

************************************************************/

For the operator < in line (2) there are two candidates:
- the user-defined template in line (1)
- the builtin operator < for enum E2

As both have the signature "bool <(E2,E2)", the built-in operator should be
hidden, and therefor the user-defined should be selected.


Here comes even more evidence, why the behaviour of the compiler seems odd:

1. 
When in the example above the user-defined template-operator is replaced by

inline bool operator<(E2, E2) {
    return true;
}


then the user-defined operator is selected.


2. When a different operator like ^, &, &&, | or || is used, then the
user-defined operator is also used (I know that the return type is odd):

/***************************************************
#include <iostream>

enum E2 {
    e2_a
};

template<class E>
inline bool operator&(E, E) {
    return true;
}


int main()
{
    if (E2::e2_a & E2::e2_a) {
        std::cout << "user-defined operator used for E2\n";
    } else {
        std::cout << "builtin operator used for E2\n";
    }
}

***************************************************/</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>