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
[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 nested-name-specifier of a type that was specified using a qualified-id.
- A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.
The nondeduced contexts are:
- The nested-name-specifier of a type that was specified using a qualified-id.
- A non-type template argument or an array bound that is an expression that references a template-parameter.
- A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
- A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (12.3 [over.over]), and one or more of the following apply:
- more than one function matches the function parameter type (resulting in an ambiguous deduction), or
- no function matches the function parameter type, or
- the set of functions supplied as an argument contains one or more function templates.
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:
- If the argument is an overload set containing one or more function templates, the parameter is treated as a nondeduced context.
- If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a nondeduced context.
[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.