9

Consider this code:

#include <type_traits>

template < typename > struct BB { };
template < >          struct BB<float> : BB<int> { };
                      struct DD : BB<float> { };

template < typename... Args >
void ff(BB<Args...>) { }

int main()
{
    ff(BB<float>{});
    ff(DD{}); // FAILS! 'BB<Args ...>' is an ambiguous base class of 'DD'
    return 0;
}

The call of ff(DD{}) fails to compile, as gcc-8.3 doesn't want to pick one from BB<float> and BB<int> (clang does the same). But BB<float> isa BB<int>, so why just BB<float> can't be picked?!

The questions are: is this according to the standard and is there a workaround while defining ff or BB to help gcc-8.3 to pick BB<float>?

SergeyA
  • 61,605
  • 5
  • 78
  • 137
Vahagn
  • 4,670
  • 9
  • 43
  • 72
  • Looks like it is a gcc bug. For what it's worth, icc19 compiles fine. I see no reason why DD should not be convertable to `BB`. – SergeyA Aug 16 '19 at 18:34
  • @SergeyA: Why should the compiler be able to deduce this correctly? How, rather? – AndyG Aug 16 '19 at 18:36
  • 1
    Same way it does here: https://godbolt.org/z/bPYajH – SergeyA Aug 16 '19 at 18:37
  • @L.F. what is the other thing it can be deduced to? (Apart from `BB`)? – SergeyA Aug 16 '19 at 18:38
  • @SergeyA: Clang chokes on OPs example. Is that also a compiler bug? – AndyG Aug 16 '19 at 18:39
  • @AndyG yes, I have recently seen a lot of confirmed compiler bugs which are exactly the same in both CLang and gcc. icc, on the other hand, is always exceptional - it normally shares no bugs from clang/gcc, and instead has it's owns – SergeyA Aug 16 '19 at 18:40
  • @SergeyA: I think icc also chokes on OPs example. – AndyG Aug 16 '19 at 18:41
  • 1
    @SergeyA: MSVC, however, handles it – AndyG Aug 16 '19 at 18:42
  • @AndyG icc19 certainly handles OPs case correctly. Just follow the link and choose icc19 – SergeyA Aug 16 '19 at 18:43
  • @SergeyA: Ah, so it does. Apologies. – AndyG Aug 16 '19 at 18:44
  • 1
    @SergeyA: I think that [temp.deduct.type] agrees with you that it should be possible to deduce the template arguments. – AndyG Aug 16 '19 at 19:03
  • @AndyG for what it's worth I also believe so, but I really don't have the energy enough to put it all together and provide a conclusive answer right now. – SergeyA Aug 16 '19 at 19:04

1 Answers1

10

This issue was the subject of CWG 2303. The committee decided to add wording "preferring 'nearer' base classes" and this wording was added to the working draft. So, in C++20, your example should instantiate ff<float>(BB<float>) whereas in C++17, it is ambiguous.

Of course, the workaround if your compiler doesn't support "C++2a" mode or if C++2a mode hasn't implemented this change yet, is to add an overload of ff that takes D.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312