6

Consider the following code:

template<typename>
struct S 
{
    operator S<int&>();  
};

template<typename T>
void f(S<T&>);

int main() 
{
    f(S<int&&>{});  // gcc ok
                    // clang error
}

gcc uses the conversion operator on the temporary argument, returning S<int&> which is matched by S<T&>, and accepts the call.

clang doesn't consider the conversion operator, fails to match T& against int&&, and rejects the call.

So what does the language say should happen here?

cigien
  • 57,834
  • 11
  • 73
  • 112
  • I was confused, please ignore that. Template argument deduction fails, overload resolution fails, and nothing more is considered, at least so I think. – Passer By Aug 26 '20 at 06:56
  • @PasserBy Yes, deduction fails, but only in one case and not the other. I want to know which one, if any, is correct. – cigien Aug 26 '20 at 06:57
  • By that I mean gcc is wrong. – Passer By Aug 26 '20 at 06:59
  • @PasserBy Ok, thanks. If you can find a bug report, that would be great. If you know *why* gcc is wrong, then an answer would be lovely as well. – cigien Aug 26 '20 at 07:01
  • gcc rejects `f(S{})`, which should be a pretty clear sign. – Passer By Aug 26 '20 at 07:03
  • @PasserBy Yeah, that seems reasonable. – cigien Aug 26 '20 at 07:08
  • 1
    [This](https://en.cppreference.com/w/cpp/language/template_argument_deduction#Implicit_conversions) could help. I guess clang is right on this one... – nop666 Aug 26 '20 at 07:45

1 Answers1

4

GCC is certainly wrong here: T& and T&& are different rows in [temp.deduct.type]/8 and are thus incompatible. Why it does so is not clear. It would make more sense to err in the other direction: if the parameter were declared as S<T&&> and the argument were of type S<int&>, there would at least be a T (i.e., int&) such that (due to reference collapsing) the parameter and argument types were the same. (There would also be the easy mistake to make to say that a universal reference was involved.)

Davis Herring
  • 36,443
  • 4
  • 48
  • 76