Reputation: 93
Given this example, which includes a few overloads:
#include <iostream>
class T
{
public:
operator const wchar_t *(void) const
{
std::cout << "Conversion" << std::endl;
return L"Testing";
}
};
template <class Elem>
class A
{
};
template <class T>
void operator <<(A<T> &, const T *)
{
std::cout << "1" << std::endl;
}
template <class T>
void operator <<(A<T> &, const void *)
{
std::cout << "2" << std::endl;
}
int main(void)
{
A<wchar_t> test;
T source;
test << L"1";
test << static_cast<const wchar_t *>(source);
test << source;
}
And its output:
1
Conversion
1
Conversion
2
My question is - why is void operator <<(A<T> &, const void *)
being called for the statement test << source;
? Can anyone cite a specific part of the standard that covers this case?
Upvotes: 3
Views: 495
Reputation: 20211
Implicit deduction of template arguments will not consider user defined implicit conversions. As such calling template <class T> void operator <<(A<T> &, const T *)
would deduce T
to be wchar_t
from the first argument, but the second argument is T
instead of const wchar_t*
. Therefore the compiler will fail to match that operator.
For template <class T> void operator <<(A<T> &, const void *)
the matter looks different: T
will be deduced to be wchar_t
from the first function argument. The second argument can be implicitly converted to const wchar_t*
by a user defined conversion, which can then be implicitly cast to a const void*
by a build in conversion. Therefore this function is callable with those arguments and is used, since the other one couldn't be deduced.
Upvotes: 0
Reputation: 154047
Because template argument deduction doesn't take user defined implicit conversions into account. The result is that when you wrote:
test << source;
, the compiler could not find a suitable T
for the first function
template; it is trying to find a T
such that T const*
has the same
type as your T
, which isn't possible. Argument deduction fails, and
no instantiation of the template is added to the overload set. Since
there's no template argument in the second parameter of the second
function template, there's no argument deduction to fail, and the
resulting instantiation becomes the only member of the overload set, and
so ends up being chosen.
Upvotes: 4
Reputation: 96311
It uses T
's implicit conversion to wchar_t
. Any type is convertible to void*
so the compiler calls that version of the operator<<
. The T*
operator was never a candidate because there was no way to get a T*
implicitly from a T
. did you mean to make it a T&
<<
operator?
Upvotes: 0