Is this program ill-formed despite SFINAE? - c++

template <typename T> void f() {
return 0; // returning value from function returning `void`
}
int main()
{
// Not instantiating or calling any f<T>()
}
In comments to this answer, David asserts that a function template that contains a semantic error and is not instantiated causes a program to be ill-formed:
Whether the template is used or not does not matter, the program is ill-formed even with no instantiation but the compiler is not required to diagnose it.
Conversely, I am quite sure that SFINAE, as well as preventing type deduction and therefore instantiation of the function template per [C++11: 14.8.2/8], allows the program to remain well-formed. however I cannot find any text in this standard paragraph that explicitly says so.
Who is correct?
Wikipedia, which I shall not consider authoritative for this question, says about a slightly different case:
[..] SFINAE was introduced to avoid creating ill-formed programs when unrelated template declarations were visible [..]
(emphasis mine)

The program is ill-formed as per 14.6/8:
If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required.
That is whether you instantiate the template or not, the template definition is ill-formed as there is no possible instantiation that will succeed.
Note that this is completely unrelated to SFINAE: Substitution Failure is not an Error is part of the substitution process, and never takes into account the contents of the template.

Reading more closely, that standard passage says:
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 if written using the substituted arguments. [..]
return 0 is not an expression, so SFINAE does not apply.
The passage goes on:
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
return 0 has nothing to do with the function type or its template parameter types, so SFINAE still does not apply.

Related

Why this example results in "substitution failure" not "hard error"

Per [temp.deduct]/8:
[..]
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.
[ Note: The substitution into types and expressions can result in
effects such as the instantiation of class template specializations
and/or function template specializations, the generation of
implicitly-defined functions, etc. Such effects are not in the
“immediate context” and can result in the program being ill-formed. —
end note ]
What I understand from the bold part is,
If the substitution process has side effects (such as instantiation of a template, etc), invalid types/expressions can result in a hard error.
If the substitution process does not have side effects, invalid types/expressions can result in a deduction failure.
If I right about what I saying above, why this program results in substitution failure and not hard error:
template <class T> struct S { using type = T; };
template <class> void f(...); // "fallback".
template <class T> struct A {};
template <class T> typename S<T>::type::type f(int);
int main(void){
f<A<int>>(0); // calls fallback. Why?
}
The above call substitutes A<int> with T. So the function type will be S<int>::type (int). Now it has to instantiate the template S<int> to check the existence of the member type. And here is the point of my question: The substitution process has side effects that result in an invalid type because S<int> specialization has no members called type. So I am expecting that the program is ill-formed instead of calling f(...).
I deliberately do not mention anything about the "immediate contexts" because I do not completely understand what this context involves/means even though there's a specific question asked here about it, but neither answer there mentions what exactly this context means. So, if possible, any side note about it will be appreciated.
So I am expecting that the program is ill-formed instead of calling f(...).
In the given example, both instantiations A<int> and S<A<int>> are well-formed by themselves. Now, even though the instantiation of A<int> and S<A<int>> is not in the immediate context of function template's substitution but S<A<int>>::type::type is.
Thus, we get a deduction failure corresponding to the expression S<A<int>>::type::type instead of getting a hard error corresponding to the instantiations A<int> and S<A<int>>.
If on the other hand, any of the instantiation were ill-formed then we would have gotten a hard error.

Partial specialization of single type template parameter class template using non-type template parameter through a dependent type

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
Consider the following snippet:
#include <type_traits>
template <int N> struct num {};
template <typename> struct A;
// (1)
template <int N> struct A<num<N>> { using type = bool; };
// (2)
template <long N> struct A<num<N>> { using type = char; };
static_assert(!std::is_same_v<long, int>, "");
// (A)
static_assert(std::is_same_v<A<num<1>>::type, bool>, "");
int main() {}
The static_assert at (A) is successful for GCC, but fails for Clang:
error: static_assert failed due to
requirement 'std::is_same_v<char, bool>' ""
Essentially, GCC picks the perfectly matching specialization (1), whereas Clang picks the specialization (2).
Similarly, if we remove the assertions as well as specialization (1):
template <int N> struct num {};
template <typename> struct A;
// (2)
template <long N> struct A<num<N>> { using type = char; };
int main() {
A<num<1>> a{};
(void)a;
}
Then GCC fails to compile the program whereas Clang accepts it.
GCC:
error: variable '`A<num<1> > a`' has initializer but incomplete type
This behaviour holds over various GCC and Clang versions, as well as various C++ language levels over these version (C++11, C++14, C++17, C++2a).
Question
Is the first snippet above in fact ill-formed (no diagnostic required?), or is either GCC or Clang wrong?
My guess is that this is ill-formed, but haven't been able to apply a relevant part of [temp.class.spec] to reject it. Perhaps [temp.class.spec]/8.1?
[temp.class.spec]/8.1 The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example: [...] — end example ]
As far as I can tell, the first snippet is ill-formed (and a diagnostic is required); compilers should reject the program because of the partial specialization (2).
[temp.deduct.type]/18 applies here:
If P has a form that contains <i>, and if the type of i differs
from the type of the corresponding template parameter of the template
named by the enclosing simple-template-id, deduction fails. [...]
The associated example in the Standard uses a function template, but is otherwise very similar.
So the template argument of the partial specialization (2) can never be deduced, and [temp.class.spec.match]/3 applies:
If the template arguments of a partial specialization cannot be
deduced because of the structure of its template-parameter-list and
the template-id, the program is ill-formed.
Interestingly, I couldn't find a compiler that diagnoses this issue, not even EDG in strict mode. We could speculate that most compiler writers consider the benefits of having a diagnostic here not to be worth the effort of implementing the checks. This could mean that we might see the requirement in the paragraph above change in the future from ill-formed to ill-formed, no diagnostic required. However, this is pure speculation. In any case, I don't see it ever changing to well-formed; I can't think of a valid use for a partial specialization that never matches.
The wording of [temp.deduct.type]/18 was clarified by the resolution of CWG2091.
The standard is not nearly precise enough about the template argument deduction for a partial specialization ([temp.class.spec.match]/2) to definitively determine the meaning of your example. In particular, all deduction is ultimately defined in terms of types ([temp.deduct.type]), but there are no types involved for a non-type template argument.
The deduction for partial ordering among partial specializations handles this case in terms of an invented class template ([temp.class.order]/1.2), which brings to bear the rule that deduction fails for any mismatch between the type of a non-type template argument and its parameter ([temp.deduct.type]/18). That makes any use of A<num<…>> in your example ambiguous if both partial specializations match (avoiding the need to determine whether a narrowing conversion was involved in using the “unique value” synthesized for partial ordering ([temp.func.order]/3) as a template argument). However, if we apply the same rule to the matching itself, we find (as does GCC) that (2) never matches. In turn, that arguably should provoke a diagnostic for the specialization itself ([temp.class.spec.match]/3, as bogdan’s answer mentioned), although it’s not entirely obvious what “structure” there is meant to include if the error is to be diagnosable and no compiler rejects it.
Meanwhile, [temp.class.spec]/8.1 is certainly irrelevant: there are no specialized non-type arguments involved.

Does the standard consider non-template members of template classes to be "templates" themselves?

Consider following code:
#include <type_traits>
template <typename T> struct A
{
static_assert(!std::is_same_v<int, T>);
};
template<typename T> struct B
{
void foo()
{
A<int>{};
}
};
int main() {}
It comes from this question on russian StackOverflow, which asks whether it's valid or not.
I attempted to reference this:
[temp.res]/8.1
8 The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
(8.1) — no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or
...
(emphasis mine)
Since no valid specialization can be generated for foo(), I reasoned that the snippet is ill-formed, NDR.
But I was told [temp.res]/8.1 doesn't apply since foo() itself isn't a template member function.
cppreference calls non-template member functions of template classes "templated entities", but it seems to be unclear if they can be considered templates themselves.
Thus, the question is: Does the standard consider non-template members of template classes to be "templates" themselves?
This is essentially CWG issue 1253
Generic non-template members
Section: 17.8 [temp.spec] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-06
Many statements in the Standard apply only to templates, for example,
17.7 [temp.res] paragraph 8:
If no valid specialization can be generated for a template definition,
and that template is not instantiated, the template definition is
ill-formed, no diagnostic required.
This clearly should apply to non-template member functions of class
templates, not just to templates per se. Terminology should be
established to refer to these generic entities that are not actually
templates.
It appears to be still in drafting. But I'd argue, like the issue, that the code in the OP should be ill-formed NDR as well. Even if the member function is never used (and therefore its full definition is never instantiated), it still cannot be even hypothetically instantiated, which puts it under the category of errors [temp.res]/8 is meant to cover.

Referring to specific template specialization from a non-instantiated context: instantiation or not?

Consider the following example
template <typename A> struct S
{
A a;
void foo() {}
};
template <typename T> void bar()
{
S<void> *p = 0;
}
template <typename T> void baz()
{
S<void>{}.foo();
}
template <typename T> void qux()
{
S<void> s{};
}
int main()
{
}
Function templates bar, baz and qux are deliberately left non-instantiated.
The definition of baz fails to compile in GCC and Clang for "obvious" reason - S<void> is an invalid specialization of S. However, which language rule is working in this case?
On the one hand, S<void> does not depend on template parameters of baz, member access requires it to be complete, which triggers instantiation of S<void>, which fails. Diagnostic is required.
On the other hand we have the blanket rule of "if no valid specialization can be generated for a non-instantiated template, the code is ill-formed". This makes the definition of baz ill-formed. However, no diagnostic is required.
More specifically, am I correct in my assumption (as expressed in #1) that the above reference to S<void> from non-instantiated baz requires instantiation of S<void>? The assumption is supported by the fact that both compilers happily accept the definition of bar, which does not instantiate S<void>.
However, the aforementioned compilers differ in their treatment of qux - Clang complains, while GCC accepts it without any complaints. Is this a bug in one of the compilers? Is diagnostic required in this case? Or am I wrong in my assumption that #1 is at work here? If #2 is the basis for the diagnostic, then the difference between the compilers is acceptable.
For both baz and qux, the validity of the expression including S<void> can only be done through instantiation of S. Nevertheless, compilers are not mandated to perform this validation before any instantiation [temp.res]/8
The validity of a template may be checked prior to any instantiation.
[...
 ] The program is ill-formed, no diagnostic required, if:
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,
Both S<void>{} and S<void> s{} are used in a context that requires the instantiation of S<void>, such an instantiation is ill-formed due to the member having incomplete type void.
The relevant quotes are [temp.inst]/1:
Unless a class template specialization has been explicitly instantiated or explicitly specialized, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. [...]
and [temp.arg]/6:
If the use of a template-argument gives rise to an ill-formed construct in the instantiation of a template specialization, the program is ill-formed.
On the other hand both baz and quz are ill-formed NDR
[temp.res]/8:
Knowing which names are type names allows the syntax of every template to be checked. The program is ill-formed, no diagnostic required, if:
(8.1) no valid specialization can be generated for a template, [...]

SFINAE and decltype(auto)

If a function template returns decltype(auto) (or another type specifier using auto) but the return statement would be ill-formed, does SFINAE result? Is the return statement considered to be the immediate context of the function signature?
Nothing in the N3690 draft seems to require this. By default, I guess SFINAE does not apply.
This seems unfortunate because you can write a function to forward to another function, but you cannot make its existence conditional on the delegate as when writing longhand. Furthermore, checking the existence of a peer nonstatic member function cannot be done without decltype(auto) because this cannot be used in a function signature. However this indicates a fundamental problem, as decltype(auto) provides a path to considering the class type as complete within a member signature, where it's not.
Has a proposal been written, or has the problem been formally analyzed anywhere?
The ability to treat the class type as complete within a member signature may have other implications… but that's just fodder for another question.
but the return statement would be ill-formed, does SFINAE result?
The proposal-n3638 says,
SFINAE
Since the return type is deduced by instantiating the template, if the instantiation is ill-formed, this causes an error rather than a substitution failure. This allows an auto function to return a lambda, which is not possible using the decltype(returned expression) pattern.
Hope that is what you're looking for.
Following up on Nawaz's link, the remaining questions are answered by N3690 §7.1.6.4/11:
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed.
This means that even if SFINAE worked with return type deduction, it couldn't be used to query one function declaration from another. The signature is essentially invalid until the return statement is processed, which occurs at the closing brace of the class {} definition, and after the definitions of preceding members have been processed.
In a sense, all member decltype(auto) functions are incomplete with respect to preceding functions in the same class:
struct s {
void f() { a(); } // error: use of ‘auto s::a()’ before deduction of ‘auto’
auto a() { return 3; }
};
This is GCC's complaint; it goes away if the member declarations are reversed. This is because the function definitions are processed in order of declaration, when the } from the class definition is reached. If the statement a(); is processed before the return 3;, then the program is ill-formed.