The following works fine (as one would expect):
struct X {};
struct A
{
operator X const& ()
{
static const X value{};
return value;
}
};
int main()
{
A a;
X x = a;
}
But this is not so clear:
template<typename T>
struct X {};
struct A
{
template<typename T>
operator X<T> const& ()
{
static const X<T> value{};
return value;
}
};
int main()
{
A a;
X<int> x = a;
}
GCC 4.9 says error: conversion from ‘A’ to non-scalar type ‘X<int>’ requested
whereas clang 3.4 has no problems with it.
If you remove the const
or the &
from the conversion function or if you write X<int> const &x = a
then GCC is happy, too.
So GCC only fails to find the conversion function if the target type is a const &
to a template class and you request a conversion to a non-const &
object of that class. Is this the correct behavior? I tried to read the standard but the overloading rules are quite confusing to me.
Yes, this is a bug in gcc. This is almost precisely core DR976, the only difference being that in their example the destination type is a non-class type:
struct F {
template<class T>
operator const T&() { static T t; return t; }
};
int main() {
F f;
int i = f; // ill-formed
}
As with your example, clang accepts and gcc rejects this example, regardless of the standard version dialect selected.
Note that the clause amended by that DR (14.8.2.3 [temp.deduct.conv]) does not discriminate between class and non-class destination types, so the resolution of that DR applies to your code equally.
Per the amended clause 14.8.2.3, the compiler should:
P
, the return type of the conversion function template, as X<T> const &
, and A
, the required result type, as X<int>
;P
, giving X<T> const
;P
, giving X<T>
;T
as int
.I would recommend filing a bug report on https://gcc.gnu.org/bugzilla/ referencing that DR.
Because in your case you are converting to a class type, there is a workaround available:
X<int> x1 = a; // fails
X<int> x2(a); // OK
X<int> x3 = X<int>(a); // also OK
In direct-initialization, constructors of the destination type are considered (8.5p16); the default copy constructor of X<int>
takes a parameter of type X<int> const&
, to which as we have already seen gcc is happy to convert a
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With