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

2024-11-11


1157. Partial ordering of function templates is still underspecified

Section: 13.7.7.3  [temp.func.order]     Status: open     Submitter: CA     Date: 2010-08-03

N3092 comment CA 7

13.7.7.3 [temp.func.order] paragraph 3 says,

To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs (13.7.4 [temp.variadic]) thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.

The characteristics of the synthesized entities and how they are determined is not specified. For example, members of a dependent type referred to in non-deduced contexts are not specified to exist, even though the transformed function type would be invalid in their absence.

Example 1:

  template<typename T, typename U> struct A;
  template<typename T> void foo(A<T, typename T::u> *) { } // #1
    // synthetic T1 has member T1::u
  template <typename T> void foo(A<T, typename T::u::v> *) { } // #2
    // synthetic T2 has member T2::u and member T2::u::v
    // T in #1 deduces to synthetic T2 in partial ordering;
    // deduced A for the parameter is A<T2, T2::u> * --this is not necessarily compatible
    // with A<T2, T2::u::v> * and it does not need to be. See Note 1. The effect is that
    // (in the call below) the compatibility of B::u and B::u::v is respected.
    // T in #2 cannot be successfully deduced in partial ordering from A<T1, T1::u> *;
    // invalid type T1::u::v will be formed when T1 is substituted into non-deduced contexts.
  struct B {
    struct u { typedef u v; };
  };
  int main() {
    foo((A<B, B::u> *)0); // calls #2
  }

Note 1: Template argument deduction is an attempt to match a P and a deduced A; however, template argument deduction is not specified to fail if the P and the deduced A are incompatible. This may occur in the presence of non-deduced contexts. Notwithstanding the parenthetical statement in 13.10.3.5 [temp.deduct.partial] paragraph 9, template argument deduction may succeed in determining a template argument for every template parameter while producing a deduced A that is not compatible with the corresponding P.

Example 2:

  template <typename T, typename U, typename V> struct A;
  template <typename T>
    void foo(A<T, struct T::u, struct T::u::u> *); // #2.1
      // synthetic T1 has member non-union class T1::u
  template <typename T, typename U>
    void foo(A<T, U , U> *); // #2.2
      // synthetic T2 and U2 has no required properties
      // T in #2.1 cannot be deduced in partial ordering from A<T2, U2, U2> *;
      // invalid types T2::u and T2::u::u will be formed when T2 is substituted in nondeduced contexts.
      // T and U in #2.2 deduces to, respectively, T1 and T1::u from A<T1, T1::u, struct
T1::u::u> * unless
      // struct T1::u::u does not refer to the injected-class-name of the class T1::u (if that is possible).
  struct B {
    struct u { };
  };
  int main() {
    foo((A<B, B::u, struct B::u::u> *)0); // calls #2.1
  }

It is, however, unclear to what extent an implementation will have to go to determine these minimal properties.