GCC incorrectly fails to compile this code template<typename T> void f(T[1]) = delete; template<typename T> void f(...); int main() { f<void>(0); } The substitution into "T" should fail, because "T[1]" is an invalid type, and hence the call should use the second template. Note that I think it's unspecified in the spec what happens when we tweak things as follows template<typename T> void f(T[1]) = delete; template<typename T> void f(T*); template<typename T> void f(...); int main() { f<void>(0); } The first two templates are equivalent, but behave different during substitution. The spec doesn't specify what the outcome of this is, I think.
I disagree. The transformation of array to pointer is done immediately at declaration time (8.3.5/6), so there is no substitution into an array type. In resolving issue 1001, core agreed that the transformations in 8.3.5/6 are done at template definition time, not deferred until the instantiation. http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1001 http://wiki.dinkumware.com/twiki/bin/view/Wg21batavia/CoreWorkingGroup#Core_issue_1001_Parameter_type_a
(In reply to comment #1) > I disagree. The transformation of array to pointer is done immediately at > declaration time (8.3.5/6), so there is no substitution into an array type. In > resolving issue 1001, core agreed that the transformations in 8.3.5/6 are done > at template definition time, not deferred until the instantiation. > > http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1001 > http://wiki.dinkumware.com/twiki/bin/view/Wg21batavia/CoreWorkingGroup#Core_issue_1001_Parameter_type_a jason, the transformation is immediately done at declaration time. I agree: That's why these two are equivalent: template<typename T> void f(T[1]); template<typename T> void f(T*); For equivalence, both shall have identical parameter-type-lists, which these have. But before argument deduction, explicit template arguments are substituted, and those explicit arguments are substituted into the *unadjusted* parameter type. See 14.8.2p3 (FDIS): "After this substitution is performed, the function parameter type adjustments described in 8.3.5 are performed." The note that contains a list of substitution failures also has an example like that at 14.8.2p8: template <class T> int f(T[5]); int I = f<int>(0); int j = f<void>(0); // invalid array
(In reply to comment #2) > (In reply to comment #1) > > I disagree. The transformation of array to pointer is done immediately at > > declaration time (8.3.5/6), so there is no substitution into an array type. In > > resolving issue 1001, core agreed that the transformations in 8.3.5/6 are done > > at template definition time, not deferred until the instantiation. > > > > http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1001 > > http://wiki.dinkumware.com/twiki/bin/view/Wg21batavia/CoreWorkingGroup#Core_issue_1001_Parameter_type_a > > jason, the transformation is immediately done at declaration time. I agree: > That's why these two are equivalent: > > template<typename T> void f(T[1]); > template<typename T> void f(T*); > > For equivalence, both shall have identical parameter-type-lists, which these > have. But before argument deduction, explicit template arguments are > substituted, and those explicit arguments are substituted into the *unadjusted* > parameter type. See 14.8.2p3 (FDIS): > > "After this substitution is performed, the function parameter type adjustments > described in 8.3.5 are performed." > > The note that contains a list of substitution failures also has an example like > that at 14.8.2p8: > > template <class T> int f(T[5]); > int I = f<int>(0); > int j = f<void>(0); // invalid array Ah I see now: The substitution for explicit arguments uses the *function type*, not the parameter types (according to p6). So in the example above, it uses "T*" and becomes "void*". It doesn't use "T[5]". p3 only applies when the dependent type was adjusted and substitution made it a non-adjusted type. So on a second read of this, I agree to you. The note at 14.8.2p8 and the example of p3 were confusing me, both tricking me into thinking that for substitution, the parameter types themselves somehow would be used.
Hmm, the example in 14.8.2p8 does seem to contradict my interpretation of the normative wording. I'll raise this with core.
(In reply to comment #4) > Hmm, the example in 14.8.2p8 does seem to contradict my interpretation of the > normative wording. I'll raise this with core. A related question, if in the end we in fact don't SFINAE or error out with "T[N]" is, whether substitution for "N" is done at all. Because the type would be "T*", not "T[N]" anymore. template<typename T> void f(char[T::size]); int main() { f<int>(); } Does the substitution succeed?
This will eventually be issue 1322, http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#1322 but the issues list hasn't been updated yet. In Bloomington we assigned it priority 1 but didn't get to discussing it.