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?
source to share
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."
source to share