5

Consider this program:

template<typename T>
struct Foo
{
    void foo(const T&) {}   
    void foo(T&) {}
};


int main()
{
    Foo<double&> f;   
    double d = 3.14;
    f.foo(d);   //complains that foo() is ambigous
}

In the above, if Foo is instantiated as Foo<double> , then things are fine, but if it is instantiated as Foo<double&>, then the call to foo becomes ambiguous. Is ref collapsing at play here when deducing the param types for foo and if so why is constness being ignored?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
MK.
  • 3,907
  • 5
  • 34
  • 46
  • What do you mean with `const`ness being ignored? Where do you use that `const`ness ? – Ely Jul 04 '17 at 17:44
  • 1
    Ok, I found the answer here - https://stackoverflow.com/a/27728034/150365 – MK. Jul 04 '17 at 17:48
  • @bolov The duplicate doesn't seem to relate. Since, in that case the OP refers to a function template and not a class template. – 101010 Jul 04 '17 at 20:03
  • @101010 yes, but the same rules/principles apply. Anyway, I don't know what happened, I see now the question is closed by T.C. – bolov Jul 05 '17 at 07:33

1 Answers1

3

Lets see what happens if we try to instatiate the Foo class template:

template<typename T>
struct Foo {
  void foo(T const&) {}   
  void foo(T&) {}
};

with template parameter double&. Substituting T with double& and according to reference collapsing rules you would get:

struct Foo {
  void foo(double& const) {}   
  void foo(double&) {}
};

Since references are inherently constant double& const is equivalent to double&. Thus, you get the following instatiation:

struct Foo {
  void foo(double&) {}   
  void foo(double&) {}
};

Here comes the compiler shouting "Dude you can't overload foo with the same signature".

A more consise error is given by CLANG:

error: multiple overloads of 'foo' instantiate to the same signature 'void (double &&)' void foo(T&) { }

Live Demo

101010
  • 41,839
  • 11
  • 94
  • 168