On Mon, 1 Jun 2026, Eczbek wrote:
> On 6/1/26 16:33, Jason Merrill wrote:
> > This assumes a template with a single template parameter; it doesn't work
> > for e.g.
> >
> > struct A {
> > template<typename T, typename U>
> > operator T U::*() {
> > return 0;
> > }
> > };
> >
> > int main() {
> > (void) &A::operator int A::*;
> > }
> >
> > to handle the general case you need to deduce the template arguments.
>
> Thanks, I did not consider multiple template parameters. Would this be
> similar to what TEMPLATE_ID_EXPR does below, or is there some existing helper
> that should be used? I'm not sure how to do this.
There are a couple of entrypoints to deduction, all of which ultimately
call the main workhorse unify. For simplicity I think we could get away
with calling unify directly from resolve_nondeduced_context with
tparms = DECL_TEMPLATE_PARMS of the conversion function template
targs = empty TREE_VEC same length as DECL_TEMPLATE_PARMS
parm = return type of the template
arg = BASELINK_OPTYPE
strict = UNIFY_ALLOW_NONE (I think?)
If unify succeeds, then 'targs' will contain the deduced template
arguments that we need to instantiate the conversion function template
with.
So for
struct A {
template<class T, class U>
operator B<T*, U&>();
};
int main() {
&A::operator B<int*, char&>;
}
we need to call unify with (where {} is shorthand for a TREE_VEC)
tparms = {T, U}
targs = {NULL, NULL}
parm = B<T*, U&>
arg = B<int*, char&>
which should succeed and fill in targs with {int, char}. Instantiating
the template with {int, char} yields the correct specialization
operator B<int*, char&>.