What normative rules govern and allow SFINAE? - c++

SFINAE, "Substitutation Failure Is Not An Error", is a well-known rule/technique applied during overload resolution of function templates (see e.g. SFINAE # cppreference). However, it is never referred to by that name in the C++ standard; the only reference I can find is that of an implementation-dependent macro from <version>, as specified in [version.syn]/2
#define __cpp_­lib_­result_­of_­sfinae 201210L // also in <functional>, <type_­traits>
What is(/are) the normative reference(s) for this rule/technique?

Let's start from an unqualified function call (f(1) below), particularly in an example constructed such that the postfix-expression of the function call names two function templates, one of which we expect to be rejected by SFINAE.
#include <type_traits>
// A: expected to be viable
template<typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
constexpr bool f(T) { return true; }
// B: expected to be rejected
template<typename T, std::enable_if_t<!std::is_integral_v<T>>* = nullptr>
constexpr bool f(T) { return false; }
static_assert(f(1));
The function call above will, as per [over.match.call.general]/1, result in overload resolution applied as specified in [over.call.func], particularly [over.call.func]/3:
[over.match.call.general]/1 In a function call
postfix-expression ( expression-list_opt )
if the postfix-expression names at least one function or function template, overload resolution is applied as specified in [over.call.func].
[over.call.func]/3 [...] The name is looked up in the context of the function call following the normal rules for name lookup in expressions ([basic.lookup]). The function declarations found by that lookup constitute the set of candidate functions. [...]
[over.match.general]/2 decribes the high-level steps of overload resolution:
Overload resolution selects the function to call in seven distinct contexts within the language:
(2.1) invocation of a function named in the function call syntax;
[...]
Each of these contexts defines the set of candidate functions and the list of arguments in its own unique way. But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
[...]
Telling us that selecting a function during overload resolution works in three different phases:
Identify the candidate functions and associated argument lists
From these, select the subset of viable functions
From these, select the best viable function based on ranking via implicit conversion sequences matching arguments with parameters
SFINAE works in the domain of 1 whilst identifying candidate functions, not so much by rejecting potential candidates but rather by failing to generate a potential candidate when such a potential candidate is a function template (specialization), particularly failing due to template deduction failures. Our example is in the context of invocation of a function named in the function call syntax, but for the context of finding the normative rules that governs SFINAE, it is representable also for other contexts as listed by [over.match.general]/2.
[over.match.funcs], particularly [over.match.funcs.general]/7 tells us that we enter the domain of template argument deduction for candidates that are function templates:
In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction ([temp.over], [temp.deduct]) [...] Those candidates are then handled as candidate functions in the usual way.
[temp.over] covers overload resolution rules specific to function templates and [temp.over]/1, in particular, contains one of two essential rules which govern SFINAE:
When a call to the name of a function or function template is written [...] template argument deduction [...] [is] performed [...] if the argument deduction and checking succeeds [...] [the] function template specialization [...] is added to the candidate functions set to be used in overload resolution. If, for a given function template, argument deduction fails or the synthesized function template specialization would be ill-formed, no such function is added to the set of candidate functions for that template.
Namely that a template argument deduction failure in the phase of finding candidate functions during overload resolution results in the function not being included in the set of candidates.
[temp.deduct] covers template argument deduction, and includes several ways in which it can fail, e.g. [temp.deduct]/2, /5, and /7, but the second essential rule which governs SFINAE is particularly found in [temp.deduct]/8:
/7 The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. [...] The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered. [...]
/8 If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments.
[...]
Only invalid types and expressions in the immediate context of the function type, its template parameter types, and its explicit-specifier can result in a deduction failure.
The latter paragraph of [temp.deduct]/8 is the reason for some notoriously tricky non-SFINAE hard failures when using generic lambdas in return type deduction. See e.g. P0238R1 for details.
If we return to the function call f(1) in the example above, the function template B will be rejected as a candidate as template argument deduction fails when replacing T in std::enable_if_t<!std::is_integral_v<T>>*, namely in the 2nd type template parameter of the template-head, with substitution of the deduced T (int) resulting in an invalid type (std::enable_if_t<!std::is_integral_v<int>>*).
[temp.deduct]/5 When all template arguments have been deduced or obtained from default template arguments, all uses of template parameters in the template parameter list of the template and the function type are replaced with the corresponding deduced or default argument values. If the substitution results in an invalid type, as described above, type deduction fails.
Finally, [temp.deduct]/5 is also where we find rules for constraints, which are not a SFINAE mechanism, but a separate step where non-satisfaction results in type deduction failure.
/5 [...] If the function template has associated constraints ([temp.constr.decl]), those constraints are checked for satisfaction ([temp.constr.constr]). If the constraints are not satisfied, type deduction fails.

Related

Deduction failure of function call with explicit template argument list and [temp.arg.explicit]/3

[temp.arg.explicit]/3 of the C++17 standard (final draft) says about deduction of function template arguments with explicitly specified template argument lists:
In contexts where deduction is done and fails, or [...], if a template argument list is specified and it, along with any default template arguments, identifies a single function template specialization, then the template-id is an lvalue for the function template specialization.
How does this apply to parameter packs?
Consider
template<typename...>
struct S {
S(int) {}
};
template<typename... A>
void f(S<A...>) {}
int main() {
f<int>(0);
}
This compiles on MSVC, but not on GCC and Clang, see godbolt. It would also be my intuition that it should fail, because deduction will fail, but the quote above seems to imply that even if deduction fails, since f<int> (in my understanding) identifies uniquely a template specialization, f<int> should be considered to refer to that specialization and then call it, without overload resolution, which will work, implicitly converting 0 to S<int>.
What is wrong in my understanding of the quote or is MSVC indeed correct?
Note that if we try to call f<>(0); (which I guess should work by the considerations above) all three compilers refuse to compile.
Relevant for the question is also [temp.arg.explicit]/6 that tells us that implicit conversions on a function parameter (as you want above) are
if the parameter type contains no template-parameters that participate in template argument deduction. [ Note: Template parameters do not participate in template argument deduction if they are explicitly specified. [...] ]
So, now is the question if A... participates in template argument deduction. (At this point I wanto to note that OPs code compiles also under gcc/clang if we replace the parameter pack by one template parameter, as it should since it is explicitly specified).
One could argue that A... is explicitly specified and therefore does not participate in deduction. But I would argue that one is wrong. [temp.arg.explicit]/9 tells us that deduction can extend explicitly specified template argument lists. Hence, f<int>(S<int, char>{0}); is valid and A... is deduced to int, char. So in this case A... definitely participates in deduction. But since this call only differs from your call by the parameter, the deduction also has to take place in your call, too.
In other words f<int>(0); could also mean to call f<int, char> and as such, it does not specify a single function template specification.
It's irrelevant. There's no such thing as a function call "without overload resolution". CWG2092 makes this clear.
[temp.over]/1 controls (broken apart for readability; emphasis mine):
When a call to the name of a function or function template is written
(explicitly, or implicitly using the operator notation), template
argument deduction ([temp.deduct]) and checking of any explicit
template arguments ([temp.arg]) are performed for each function
template to find the template argument values (if any) that can be
used with that function template to instantiate a function template
specialization that can be invoked with the call arguments.
For each function template, if the argument deduction and checking succeeds,
the template-arguments (deduced and/or explicit) are used to
synthesize the declaration of a single function template
specialization which is added to the candidate functions set to be
used in overload resolution.
If, for a given function template,
argument deduction fails or the synthesized function template
specialization would be ill-formed, no such function is added to the
set of candidate functions for that template. The complete set of
candidate functions includes all the synthesized declarations and all
of the non-template overloaded functions of the same name. The
synthesized declarations are treated like any other functions in the
remainder of overload resolution, except as explicitly noted in
[over.match.best].
There is an open core language issue (issue 2055: Explicitly-specified non-deduced parameter packs) that is well related to this case.
From my understanding of what is implictly stated in this issue, the intent is that compilers should behave as MSVC but the standard is said not to be clear enough.

template with lambda as unique default parameter on each instantiation

I'm looking for a way to automatically make default template parameter be unique each time a template is instantiated. Since unnamed function objects created by lambda expressions have different types I thought of adopting them somehow. With recent changes to standard daft removing "A lambda-expression shall not appear in ... a template-argument" restriction (see Wording for lambdas in unevaluated contexts) it seemed like a good idea. So I wrote the following kinda working snippet that compiles on recent gcc and clang:
#include <type_traits>
template<void ( * ) (void) = [](){}> class
unique final {};
static_assert(false == ::std::is_same_v<unique<>, unique<>>);
int main()
{
return 0;
}
Is this a viable approach or one of those "ill-formed, no diagnostic is required" cases?
Some additional context: I want to use this to implement Ada-style strong type definitions that should work in a single translation unit without manually inventing unique tags that would be otherwise unused:
struct _tag_WowInt {};
using Int = type<int, _tag_WowInt>;
struct _tag_SoUnique {};
using DifferentInt = type<int, _tag_SoUnique>;
Upd1: I would like to mention that approaches involving __COUNTER__ or similar macros won't work in general case because they will be expanded by preprocessor only once and won't yield unique types when used inside of template for example.
I believe that you are right, it seems to me that is "ill-formed, no diagnostic required". I think this is covered by
[temp.res/8.4] and [temp.res/8.5]:
(8.4) ― a hypothetical instantiation of a template immediately following its definition would be ill-formed due to
a construct that does not depend on a template parameter, or
(8.5) ― the interpretation of such a construct in the hypothetical instantiation is different from the interpretation
of the corresponding construct in any actual instantiation of the template. [Note: This can happen in situations including the following:
(8.5.1) ― a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is performed, or
(8.5.2) ― lookup for a name in the template definition found a using-declaration, but the lookup in the corresponding scope in the instantiation does not find any declarations because the using-declaration was a pack expansion and the corresponding pack is empty, or
(8.5.3) ― an instantiation uses a default argument or default template argument that had not been defined at the point at which the template was defined, or
(8.5.4) ― constant expression evaluation within the template instantiation uses
(8.5.4.1) ― the value of a const object of integral or unscoped enumeration type or
(8.5.4.2) ― the value of a constexpr object or
(8.5.4.3) ― the value of a reference or
(8.5.4.4) ― the definition of a constexpr function,
and that entity was not defined when the template was defined, or
(8.5.5) ― a class template specialization or variable template specialization that is specified by a non-dependent simple-template-id is used by the template, and either it is instantiated from a partial specialization that was not defined when the template was defined or it names an explicit specialization that was not declared when the template was defined.
— end note]
Even though your use case is not explicitly listed in the examples of the note, in my understanding the requirement implies that unique<> must refer to the same thing throughout the whole program, otherwise it is ill-formed, no diagnostic required.
This was CWG1850. The Committee appear to dislike this
kind of stateful meta-programming. The constexpr counter no longer works
in newer versions of the compilers.

Seemingly defective paragraph regarding template argument deduction?

Omitting a template argument is possible, since the standard says in 17.9.1, paragraph 3 [temp.arg.explicit] (N4700):
Trailing template arguments that can be deduced or obtained from default template-arguments may be omitted from the list of explicit template-arguments...
On the other hand, the standard has a conflicting rule, as 17.9.2, paragraph 2 [temp.deduct] shows (emphasis mine):
... Specifically, the following steps are performed when evaluating an explicitly specified template argument list with respect to a given function template:
If the specified template arguments do not match the template parameters in kind (i.e., type, non-type, template), or if there are more arguments than there are parameters and no parameter is a template parameter pack, or if there is not an argument for each non-pack parameter, type deduction fails.
...
This paragraph suggests that all template arguments shall be specified if we were to use a explicit template argument list, which clearly contradicts to the above paragraph. Then, what's the intention?
The second quote applies "when evaluating an explicitly specified template argument list", but the first clearly is about the case when some template arguments are not explicitly specified. There's no conflict, because they're talking about two different situations.

Template argument deduction for variadic function pointer parameter - handling of ambiguous cases

Consider the following code:
#include <iostream>
void f(int) { }
void f(int, short) { }
template<typename... Ts> void g(void (*)(Ts...))
{
std::cout << sizeof...(Ts) << '\n';
}
template<typename T, typename... Ts> void h(void (*)(T, Ts...))
{
std::cout << sizeof...(Ts) << '\n';
}
int main()
{
g(f); // #1
g<int>(f); // #2
h(f); // #3
h<int>(f); // #4
}
The intent is to try each of the lines in the body of main() separately. My expectations were that all four calls were ambiguous and would result in compiler errors.
I tested the code on:
Clang 3.6.0 and GCC 4.9.2, both using -Wall -Wextra -pedantic -std=c++14 (-std=c++1y for GCC) - same behaviour in all these cases, except for minor differences in the wording of error messages;
Visual C++ 2013 Update 4 and Visual C++ 2015 CTP6 - again, same behaviour, so I'll call them "MSVC" going forward.
Clang and GCC:
#1: Compiler error, with a confusing message, basically no overload of 'f' matching 'void (*)()'. What? Where did the no-param declaration come from?
#3: Compiler error, with another confusing message: couldn't infer template argument 'T'. Of all the things that could fail there, deducing the argument for T would be the last one I would expect...
#2 and #4: Compiles with no errors and no warnings, and chooses the first overload.
For all four cases, if we eliminate one of the overloads (any one), the code compiles fine and chooses the remaining function. This looks like an inconsistency in Clang and GCC: after all, if deduction succeeds for both overloads separately, how can one be chosen over the other in cases #2 and #4? Aren't they both perfect matches?
Now, MSVC:
#1, #3 and #4: Compiler error, with a nice message: cannot deduce template argument as function argument is ambiguous. Now that's what I'm talking about! But, wait...
#2: Compiles with no errors and no warnings, and chooses the first overload. Trying the two overloads separately, only the first one matches. The second one generates an error: cannot convert argument 1 from 'void (*)(int,short)' to 'void (*)(int)'. Not so good anymore.
To clarify what I'm looking for with case #2, this is what the standard (N4296, first draft after C++14 final) says in [14.8.1p9]:
Template argument deduction can extend the sequence of template
arguments corresponding to a template parameter pack, even when the
sequence contains explicitly specified template arguments.
Looks like this part doesn't quite work in MSVC, making it choose the first overload for #2.
So far, it looks like MSVC, while not quite right, is at least relatively consistent. What's going on with Clang and GCC? What's the correct behaviour according to the standard for each case?
As far as I can tell, Clang and GCC are right in all four cases according to the standard, even though their behaviour may seem counter-intuitive, especially in cases #2 and #4.
There are two main steps in the analysis of the function calls in the code sample. The first one is template argument deduction and substitution. When that completes, it yields a declaration of a specialization (of either g or h) where all template parameters have been replaced with actual types.
Then, the second step attempts to match f's overloads against the actual pointer-to-function parameter that was constructed in the previous step. The best match is chosen according to the rules in [13.4] - Address of overloaded function; in our cases this is pretty simple, as there are no templates among the overloads, so we have either one perfect match or none at all.
The key point to understanding what happens here is that an ambiguity in the first step doesn't necessarily mean that the whole process fails.
The quotes below are from N4296 but the content hasn't changed since C++11.
[14.8.2.1p6] describes the process of template argument deduction when a function parameter is a pointer to function (emphasis mine):
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 non-deduced 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 the deduction. If deduction succeeds for more than one
member of the overload set the parameter is treated as a non-deduced
context.
For completeness, [14.8.2.5p5] clarifies that the same rule applies even when there's no match:
The non-deduced contexts are: [...]
— A function parameter for which argument deduction cannot be done because
the associated function argument is a function, or a set of overloaded
functions (13.4), 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.
So, no hard errors because of ambiguity in these cases. Instead, all template parameters are in non-deduced contexts in all our cases. This combines with [14.8.1p3]:
[...] A trailing template parameter pack (14.5.3) not otherwise
deduced will be deduced to an empty sequence of template arguments.
[...]
While the use of the word "deduced" is confusing here, I take this to mean that a template parameter pack is set to the empty sequence if no elements can be deduced for it from any source and there are no template arguments explicitly specified for it.
Now, the error messages from Clang and GCC start to make sense (an error message that only makes sense after you understand why the error occurs is not exactly the definition of a helpful error message, but I guess it's better than nothing):
#1: Since Ts is the empty sequence, the parameter of g's specialization is indeed void (*)() in this case. The compiler then tries to match one of the overloads to the destination type and fails.
#3: T only appears in a non-deduced context and is not explicitly specified (and it's not a parameter pack, so it cannot be "empty"), so a specialization declaration cannot be constructed for h, hence the message.
For the cases that do compile:
#2: Ts cannot be deduced, but one template parameter is explicitly specified for it, so Ts is int, making g's specialization's parameter void (*)(int). The overloads are then matched against this destination type, and the first one is chosen.
#4: T is explicitly specified as int and Ts is the empty sequence, so h's specialization's parameter is void (*)(int), the same as above.
When we eliminate one of the overloads, we eliminate the ambiguity during template argument deduction, so the template parameters are no longer in non-deduced contexts, allowing them to be deduced according to the remaining overload.
A quick verification is that adding a third overload
void f() { }
allows case #1 to compile, which is consistent with all of the above.
I suppose things were specified this way to allow template arguments involved in pointer-to-function parameters to be obtained from other sources, like other function arguments or explicitly-specified template arguments, even when template argument deduction can't be done based on the pointer-to-function parameter itself. This allows a function template specialization declaration to be constructed in more cases. Since the overloads are then matched against the parameter of the synthesized specialization, this means we have a way to select an overload even if template argument deduction is ambiguous. Quite useful if this is what you're after, terribly confusing in some other cases - nothing unusual, really.
The funny thing is that MSVC's error message, while apparently nice and helpful, is actually misleading for #1, somewhat but not quite helpful for #3, and incorrect for #4. Also, its behaviour for #2 is a side effect of a separate problem in its implementation, as explained in the question; if it weren't for that, it would probably issue the same incorrect error message for #2 as well.
This is not to say that I like Clang's and GCC's error messages for #1 and #3; I think they should at least include a note about the non-deduced context and the reason it occurs.

Is there any guarantee on the order of substitution in a function template after type deduction?

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.
[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.