Difference in behavior between ambiguous base class conversions in Clang and GCC

The following prints -1

in GCC 4.9 , VC ++, but prints 2

in Clang 3.5 :

template <int n>
struct base { static constexpr int value = n; };

struct A : base<0> { };
struct B : base<1> { };
struct C : base<2> { };

struct D : A, B, C { };

template <int n>
base<n> base_cast(base<n>);

template <typename T, typename B = decltype(base_cast(std::declval<T>()))>
std::integral_constant<int, B::value> f(int);

template <typename T>
std::integral_constant<int, -1> f(...);

constexpr int value = decltype(f<D>(0))::value;

int main()
{
    std::cout << value << std::endl;
}

      

I say clang is wrong because there are multiple conversions from D

to base<n>

: through A

, B

and C

. The weird thing clang does is that it seems to convert to the last base class in its list of base specifiers.

Is this a bug in Clang? May I have actual wording from the standard?

+3


source to share


1 answer


Clause 4 of the Standard applies to standard conversions:

4.2 [Note: expressions with a given type will be implicitly converted to other types in several contexts:

- When used as a source expression for initialization (which includes using it as an argument in a function call and using it as an expression in a return statement). The type of the object being initialized is (usually) the type of the destination. See 8.5, 8.5.3.

-end note]

4.3. The expression e can be implicitly converted to type T if and only if the declaration T t = e; well formed, for some contrived time variable t (8.5)


Based on this, D can be converted to base <0> base <1> base <2>.

base<0> b0 = D(); //compiles
base<1> b1 = D(); //compiles
base<2> b2 = D(); //compiles

      



Since there are three possible conversions, calling base_cast should result in an ambiguous call.


The following piece of code:

template <int n>
void print_base(base<n>)
{
   std::cout << n << std::endl;
}
...
print_base(D());

      

gives the following error in gcc 4.7.2:

error: no matching function for call to 'print_base(D)'
 note: candidate is:
 note: template<int n> void print_base(base<n>)
 note:   template argument deduction/substitution failed:
 note:   'D' is an ambiguous base class of 'base<n>'

      


The error message looks a little bit here: "D" is ambiguous "→ base <n>, but it conveys a dot."

+1


source







All Articles