Templated operator overloading

Hi all,

I have some small problem with clang behavior in such code:

struct stream
{
     stream() {}
     template<typename T>
     inline stream& operator<<(T& t)
     {
         return *this;
     }
};

template<typename Stream>
inline Stream& operator<<(Stream& stream, int& t)
{
     return stream;
}

int main(int argc, char *argv[])
{
     int i = 42;
     stream a;
     a << i;

     return 0;
}

This code compiles fine under clang (I have checked with 3.4 and current trunk) and gcc. However when I add -std=c++11 it still compiles fine under gcc but it stops compiling under clang. Error is:

/home/abuszta/Development/llvm/bin/clang++ -std=c++11 operator.cpp -o operator
operator.cpp:21:7: error: use of overloaded operator '<<' is ambiguous (with operand types 'stream' and 'int')
     a << i;
     ~ ^ ~
operator.cpp:5:20: note: candidate function [with T = int]
     inline stream& operator<<(T& t)
                    ^
operator.cpp:12:16: note: candidate function [with Stream = stream]
inline Stream& operator<<(Stream& stream, int& t)
                ^
1 error generated.

In order to answer the question which behavior is good and which is bad I tried to find appropriate section in C++ standard. After analyzing 14.5.6.2 (section about Partial ordering of function templates in N3337) and related I think there should not be any ambiguity after substitution and function should be choosed...

What is more, when I make const stream a; this code compiles fine even with -std=c++11 and chooses the standalone function in favor to member function which suggests that there may be some problem with template resolution here.

What is your interpretation of this behavior? Should I report bug?

Best regards,
Antoni Buszta.

Hi all,

I have some small problem with clang behavior in such code:

struct stream
{
    stream() {}
    template<typename T>
    inline stream& operator<<(T& t)
    {
        return *this;
    }
};

template<typename Stream>
inline Stream& operator<<(Stream& stream, int& t)
{
    return stream;
}

int main(int argc, char *argv[])
{
    int i = 42;
    stream a;
    a << i;

    return 0;
}

This code compiles fine under clang (I have checked with 3.4 and current
trunk) and gcc. However when I add -std=c++11 it still compiles fine under
gcc but it stops compiling under clang. Error is:

/home/abuszta/Development/llvm/bin/clang++ -std=c++11 operator.cpp
-o operator
operator.cpp:21:7: error: use of overloaded operator '<<' is ambiguous
(with operand types 'stream' and 'int')
    a << i;
    ~ ^ ~
operator.cpp:5:20: note: candidate function [with T = int]
    inline stream& operator<<(T& t)
                   ^
operator.cpp:12:16: note: candidate function [with Stream = stream]
inline Stream& operator<<(Stream& stream, int& t)
               ^
1 error generated.

See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#532

Deduction succeeds for both function templates, and neither candidate is
better than the other based on implicit conversion sequences, so we perform
partial ordering on the function templates. Per 14.5.6.2, we perform
partial ordering on these signatures:

stream &(stream &, T &) // member
Stream &(Stream &, int &) // non-member

These are unordered, so the call is ambiguous.

In C++98 mode, we don't implement DR532, and instead only consider the
second parameter. That's arguably misguided, since the wording prior to
DR532 was simply broken (in particular, it didn't say that we ignore the
first parameter from the non-member, which is what we do in C++98 mode),
and we'd be better off using the C++11 rule rather than making up a
different rule.

Apparently GCC doesn't implement DR532 in any mode.

In order to answer the question which behavior is good and which is bad I

tried to find appropriate section in C++ standard. After analyzing 14.5.6.2
(section about Partial ordering of function templates in N3337) and related
I think there should not be any ambiguity after substitution and function
should be choosed...

What is more, when I make const stream a; this code compiles fine even
with -std=c++11 and chooses the standalone function in favor to member
function which suggests that there may be some problem with template
resolution here.

What is your interpretation of this behavior? Should I report bug?

This is a GCC bug. And possibly a bug in Clang's C++98 mode, depending on
your point of view.

This sounds like http://llvm.org/bugs/show_bug.cgi?id=12961 to me. But it’s not clear if this is expected or not.

I somehow missed your reply Richard. Is the bug report I showed earlier the same thing? And should we close it if it is?

I somehow missed your reply Richard. Is the bug report I showed earlier
the same thing? And should we close it if it is?

Yes, that bug is the same thing. I think we should extend this behavior to
C++98 mode, and then close the bug (if you're interested, look for
CPlusPlus11 in SemaTemplateDeduction; this is the second and third
occurrence).

And what would be the best thing to do with temp.func.order\p3.cpp? Mark it as expected-error and put a comment that we’ve extended DR532 to cover C++98/03?

And what would be the best thing to do with temp.func.order\p3.cpp? Mark
it as expected-error and put a comment that we've extended DR532 to cover
C++98/03?

Please merge p3.cpp and p3-0x.cpp together and run it in both C++98 and
C++11 modes. In C++98 mode, #ifdef out the part that tests ref-qualifiers.