This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-10-26


352. Nondeduced contexts

Section: 13.10.3.2  [temp.deduct.call]     Status: CD1     Submitter: Andrei Iltchenko     Date: 24 April 2002

[Voted into WP at March 2004 meeting.]

The current definition of the C++ language speaks about nondeduced contexts only in terms of deducing template arguments from a type 13.10.3.6 [temp.deduct.type] paragraph 4. Those cases, however, don't seem to be the only ones when template argument deduction is not possible. The example below illustrates that:

namespace  A  {
   enum  ae  {   };
   template<class R, class A>
   int  foo(ae, R(*)(A))
   {   return  1;   }
}

template<typename T>
void  tfoo(T)
{   }

template<typename T>
int  tfoo(T)
{   return  1;   }

/*int  tfoo(int)
{   return  1;   }*/


int  main()
{
   A::ae   a;
   foo(a, &tfoo);
}

Here argument-dependent name lookup finds the function template 'A::foo' as a candidate function. None of the function template's function parameter types constitutes a nondeduced context as per 13.10.3.6 [temp.deduct.type] paragraph 4. And yet, quite clearly, argument deduction is not possible in this context. Furthermore it is not clear what a conforming implementation shall do when the definition of the non-template function '::tfoo' is uncommented.

Suggested resolution:

Add the following as a new paragraph immediately before paragraph 3 of 13.10.3.2 [temp.deduct.call]:

After the above transformations, in the event of P being a function type, a pointer to function type, or a pointer to member function type and the corresponding A designating a set of overloaded (member) functions with at least one of the (member) functions introduced by the use of a (member) function template name (12.3 [over.over]) or by the use of a conversion function template (13.10.3.4 [temp.deduct.conv]), the whole function call expression is considered to be a nondeduced context. [Example:

namespace  A  {
   enum  ae  {   };
   template<class R, class A>
   int  foo(ae, R(*)(A))
   {   return  1;   }
}

template<typename T>
void  tfoo(T)
{   }

template<typename T>
int  tfoo(T)
{   return  1;   }

int  tfoo(int)
{   return  1;   }

int  main()
{
   A::ae   a;
   foo(a, &tfoo);   //  ill-formed, the call is a nondeduced context
   using  A::foo;
   foo<void,int>(a, &tfoo);  // well-formed, the address of the spe-
                             // cialization 'void tfoo<int>(int)' is
                             // the second argument of the call
}

Notes from October 2002 meeting:

There was agreement that deduction should fail but it's still possible to get a result -- it's just not a "nondeduced context" in the sense of the standard.

The presence of a template in the overload set should not automatically disqualify the overload set.

Proposed Resolution (April 2003, revised October 2003):

In 13.10.3.6 [temp.deduct.type] paragraph 4 replace:

The nondeduced contexts are:
with:
The nondeduced contexts are:

In 13.10.3.2 [temp.deduct.call], add after paragraph 3:

When P is a function type, pointer to function type, or pointer to member function type:

[Example:

// Only one function of an overload set matches the call so the function
// parameter is a deduced context.
template <class T> int f(T (*p)(T));
int g(int);
int g(char);
int i = f(g);  // calls f(int (*)(int))
--end example]

[Example:

// Ambiguous deduction causes the second function parameter to be a
// nondeduced context.
template <class T> int f(T, T (*p)(T));
int g(int);
char g(char);
int i = f(1, g);  // calls f(int, int (*)(int))
--end example]

[Example:

// The overload set contains a template, causing the second function
// parameter to be a nondeduced context.
template <class T> int f(T, T (*p)(T));
char g(char);
template <class T> T g(T);
int i = f(1, g);  // calls f(int, int (*)(int))
--end example]

In 13.10.3.6 [temp.deduct.type] paragraph 14, replace:

If, in the declaration of a function template with a non-type template-parameter, the non-type template-parameter is used in an expression in the function parameter-list, the corresponding template-argument must always be explicitly specified or deduced elsewhere because type deduction would otherwise always fail for such a template-argument.
With:
If, in the declaration of a function template with a non-type template parameter, the non-type template parameter is used in an expression in the function parameter list, the expression is a nondeduced context.

Replace the example with:

[Example:
template<int i> class A { /* ... */ };
template<int i> void g(A<i+1>);
template<int i> void f(A<i>, A<i+1>);
void k() {
  A<1> a1;
  A<2> a2;
  g(a1);  //error: deduction fails for expression i+1
  g<0>(a1); //OK
  f(a1, a2);  // OK
}
--end example]

In 13.10.3.6 [temp.deduct.type] paragraph 16, replace:

A template-argument can be deduced from a pointer to function or pointer to member function argument if the set of overloaded functions does not contain function templates and at most one of a set of overloaded functions provides a unique match.

With:

A template-argument can be deduced from a function, pointer to function, or pointer to member function type.