11
votes

Consider this function template:

template<typename T>
typename soft_error<T>::type foo(T, typename hard_error<T>::type)
{ }

After deducing type T from the type of the first argument in the call to foo(), the compiler will proceed to substitute T and instantiate the function signature.

If substitution for the return type gets executed first, causing a simple substitution failure, the compiler will discard this function template when computing the overload set and search for other viable overloads (SFINAE).

On the other hand, if substitution for the second function parameter occurs first, causing a hard error (e.g. because of a substitution failure in a non-immediate context), the entire compilation would fail.

QUESTION: Is there any guarantee on the order in which substitution will be performed for the function parameters and return types?


NOTE: This example seems to show that on all major compilers (VC11 was tested separately and gave identical results) substitution for the return type occurs before substitution for the parameter types.

1
@NicolBolas: Right, that's because substitution is actually meant to happen in lexical order - btw Xeo correctly pointed out that this is not the behavior prescribed by the current standard, so I corrected my answerAndy Prowl

1 Answers

14
votes

[NOTE: This was not originally meant to be a self-answered question, but I happened to find out the solution while crafting the question]


Is there any guarantee on the order in which substitution will be performed for the function parameters and return types?

Not in the current standard.

However, this Defect Report (courtesy of Xeo) shows that this is indeed intended to be the case. Here is the proposed new wording for Paragraph 14.8.2/7 of the C++11 Standard (which has become part of the n3485 draft):

The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions. The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered. [...]

As correctly pointed out by Nicol Bolas in the comments to the question, lexical order means that a trailing return type would be substituted after the parameter types, as shown in this live example.