Caesar Caesar - 2 months ago 10
C++ Question

C++-conversion function template deduction, why does this work?

class A
{
struct B{};
public:
static void test(A::B){}
};

struct C
{
template<class T>
operator T()
{
return T();
}
};

int main()
{
A::test(C());
}


This code works for clang 3.7, gcc 5.1 and vc++ 14.2.

2 problems,

1. Why can template deduce the type is A::B? (so smart!)

As far as I know, template deduce the type by return statement instead of parameter.

But I found something interested in N4606 12.3.2 6
A conversion function template shall not have a deduced return type (7.1.7.4).
(However, I cannot find further information about this, because 7.1.7.4 is too hard to understand.)

2. Why could conversion function template access A::B?

Thanks.

Answer
  1. Why can template deduce the type is A::B? (so smart!)

Since test() takes an A::B, you need a way to convert a C to an A::B. We can attempt an initialization by conversion function, for which we have in [over.match.conv]:

The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions.

We perform template deduction according to [temp.conv]:

Template argument deduction is done by comparing the return type of the conversion function template (call it P) with the type that is required as the result of the conversion (call it A; see 8.6, 13.3.1.5, and 13.3.1.6 for the determination of that type) as described in 14.8.2.5.

Basically, we deduce the T in template <class T> operator T() to be A::B. This is a well-formed conversion sequence, and the only viable one, so that's what happens.

The line you quote, about "deduced return type", refers to auto or decltype in the return type. This doesn't happen here.

  1. Why could conversion function template access A::B?

Access rules are strictly about names. The name B, and only the name, is private to A. But we're not accessing the name, we're deducing the type directly.

B's constructor is public, so the body of the conversion function is also well-formed, so everything about the code is well-formed.

Comments