SFINAE and decltype(auto) - c++

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.

Related

Concept is satisfied by a type that would seemingly produce an invalid expression

In the following code, the can_foo concept tests whether or not a foo() member function can be called on an instance of a type. I will use it to test instances of two templates: base conditionally enables the foo member function, and derived overrides foo to call into its base's implementation:
template <typename T>
concept can_foo = requires(T v) {
v.foo();
};
template <bool enable_foo>
struct base {
void foo()
requires enable_foo
{}
};
template <typename T>
struct derived : T {
void foo()
{
static_cast<T&>(*this).foo();
}
};
If I test whether instances of the base template satisfy the concept, it does what I would expect:
static_assert(can_foo<base<true>>); //okay
static_assert(not can_foo<base<false>>); //okay
When I wrap those types in derived, I see:
static_assert(can_foo<derived<base<true>>>); //okay
static_assert(not can_foo<derived<base<false>>>); //error: static assertion failed
This is surprising! I expected that derived<base<false>> would not satisfy can_foo - its definition of foo uses an expression that isn't valid given T = base<false>, and using the same expression tested by the concept in an evaluated context results in an error that says as much:
int main()
{
derived<base<false>> v{};
v.foo(); //error
}
The error message isn't at the call site, which is probably relevant; it references the body of derived<>::foo. From clang:
<source>:18:32: error: invalid reference to function 'foo': constraints not satisfied
static_cast<T&>(*this).foo();
^
<source>:31:7: note: in instantiation of member function 'derived<base<false>>::foo' requested here
v.foo(); //"invalid reference to function 'foo'"
^
<source>:10:18: note: because 'false' evaluated to false
requires enable_foo
^
clang: https://godbolt.org/z/vh58TTPxo
gcc: https://godbolt.org/z/qMPrzznar
Both compilers produce the same results, so I assume the problem is that there's a subtlety in the standard that I'm missing. Adding a can_foo<T> constraint to derived<T> or derived<T>::foo "fixes" this (that is, derived<base<false>> will no longer satisfy can_foo), and in a code review I would argue that this constraint should be present - but this is surprising behaviour nonetheless and I'd like to understand what's going on.
So: why does derived<false> satisfy can_foo?
A requires-expression can only detect invalid constructs in the "immediate context" of the expression that is tested. In particular
requires(T v) {
v.foo();
};
will not check whether it is actually well-formed to have the call v.foo(). If v.foo() would be ill-formed due to an ill-formed construct inside the body of the foo function, this will not be detected by the requires-expression because the body is not in the immediate context.
The question is, what should happen next? Should the requires-expression go and instantiate the body of foo and give a hard error, or should it return true and give you a hard error later when you attempt to call v.foo()? The answer is the second one: instantiation is not performed because it is not required. See [temp.inst]/5
Unless a function template specialization is a declared specialization, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. [...]
[temp.inst]/11 additionally implies that the implementation is not permitted to instantiate the definition unless it is required.
In an unevaluated context, calling v.foo() does not require the definition of foo to exist, because it is not odr-used unless it is potentially evaluated and it is normally the ODR that requires a definition to exist. (However, there are two situations where referencing a function requires its definition to exist even in an unevaluated context: when the function has a deduced return type or is needed for constant evaluation ([temp.inst]/8)). Since the definition is not required to exist, the definition is not instantiated.
You might want to modify derived::foo so that it propagates the constraint from T::foo, and thus the ill-formedness can be detected by can_foo<derived<T>>:
void foo() requires can_foo<T> {
static_cast<T&>(*this).foo();
}
derived has a foo for every template parameter T, it just cannot always be instantiated. When trying to instantiate derived<base<false>>::foo where you try to to call it in main, you get the error message that the instantiation is not valid since foo cannot be called for the type base<false>.
Rules regarding when instantiation is optional and/or required in the standard would be [temp.inst].
I'm however not able to point to a conclusive passage that says that
checking whether derived<base<false>>::foo exists in the context of the static_assert does not require instantiation. Is it the same as overload resolution checking? "If the function selected by overload resolution can be determined without instantiating a class template definition, it is unspecified whether that instantiation actually takes place."
If you want derived::foo to only be available if it can be instantiated, you could require can_foo on its T.
template <typename T>
struct derived : T {
void foo() requires can_foo<T>
{
static_cast<T&>(*this).foo();
}
};
https://godbolt.org/z/EqrMq4Moq

Can a type be defined inside a template parameter list in C++?

In the following definition of template struct B, a lambda is used as a default value of a non-type template argument, and in the body of the lambda some type A is defined:
template <auto = []{ struct A{}; }>
struct B {};
Clang and MSVC are fine with this definition, but GCC complains:
error: definition of 'struct<lambda()>::A' inside template parameter list
Demo: https://gcc.godbolt.org/z/f1dxGbPvs
Which compiler is right here?
[temp.param]/2 says:
Types shall not be defined in a template-parameter declaration.
Taking this as written, GCC is correct to reject this code: this prohibition is not constrained to type-id of a type parameter, but applies to anywhere within template parameter declaration. Including nested within a lambda.
This sentence was added as a result of DR 1380 (N3481), which reveals it was considered already implied by what now I am guessing to be [dcl.fct]/17:
Types shall not be defined in return or parameter types.
This, however, only seems to apply to the type of the parameter declared and not to the initializer-clause.
On the other hand, one might also read it as prohibiting lambdas themselves in template parameters. After all, a lambda expression implicitly defines a class type ([expr.prim.lambda.closure]/1).
On the third hand, we also have [expr.prim.lambda.closure]/2, which states:
The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression.
The relevant scope here seems to be the namespace scope. This would imply the lambda should be treated as if its type were declared outside the template parameter list. But then, so should be declarations inside the body of the lambda, and the definition in the question should be allowed.
Personally, I consider it a defect in the standard that the scope of this prohibition seems so ill-defined.

Overload function template by return type

I accidentally find the following two templates can be overloaded(don't incur a name redefined error), which I think is counter-intuitive.
template<typename T>
void func(T) {}
template<typename T>
int func(T) {return 0;}
From cppreference.com, there is a related paragraph:
When an expression that uses type or non-type template parameters
appears in the function parameter list or in the return type, that
expression remains a part of the function template signature for the
purpose of overloading:
But the return types of those two functions don't include T. Who can explain it for me?
Your paragraph quoted is irrelevant.
There is a special rule to prevent non-template functions that differ only in the return type from being overloaded (from the standard [over.load]/2.1):
Function declarations that differ only in the return type, the exception specification, or both cannot be overloaded.
So the program is ill-formed if such declarations exist (even if the program does not call them). However, this rule neither applies to function templates, nor to template specializations synthesized for the purpose of overload resolution according to [over.load]/1.
Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A program is ill-formed if it contains two such non-overloadable declarations in the same scope. [ Note: This restriction applies to explicit declarations in a scope, and between such declarations and declarations made through a using-declaration. It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). — end note ]
So these two templates can be well overloaded.
However, as Dean Seo said in his answer, if you try to call func, the program would be ill-formed due to the ambiguity of overload resolution.
the following two templates can be overloaded(don't incur a name redefined error), which I think is counter-intuitive.
Not really.
The two functions can't be overloaded, but the compiler just does not know their existence until the very moment of them being instantiated:
// Try invoking `func`
func(0xFF);
Now the compiler will throw an error message similar to:
error: call to 'func' is ambiguous

Does a declaration using "auto" match an extern declaration that uses a concrete type specifier?

Consider the following program:
extern int x;
auto x = 42;
int main() { }
Clang 3.5 accepts it (live demo), GCC 4.9 and VS2013 do not (live demo for the former). Who is right, and where is the correct behavior specified in the C++ Standard?
There's surprisingly little in the standard about this. About all we hear about redeclaration is:
[C++11: 3.1/1]: A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations. [..]
and the only relevant part of auto's semantics:
[C++11: 7.1.6.4/3]: Otherwise, the type of the variable is deduced from its initializer. [..]
(reminding us that the type of x is int).
We know that a variable must be given the same type by all declarations:
[C++11: 3.5/10]: After all adjustments of types (during which typedefs (7.1.3) are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound (8.3.4). A violation of this rule on type identity does not require a diagnostic.
and the "after all adjustments of types" ought to take care of any questions regarding auto's participation in all of this; my interpretation, then, is that this is inherently a valid redeclaration (and definition) of the x at global scope with type int, and that Clang is correct. Even if we propose that auto does not count as "adjustment of type", since no diagnostic is required, at worst all listed implementations are compliant in their own way.
I believe GCC and Visual Studio are taking the following as inspiration:
[C++11: 7.1.6.4/5]: A program that uses auto in a context not explicitly allowed in this section is ill-formed.
…but I think that this is short-sighted. It seems unlikely that the standard language is intended to prohibit the usual redeclaration rules, just because they are not repeated or explicitly referenced from within 7.1.6.4.
C++14 adds wording that relates to declarations of functions with deduced types:
[C++14: 7.1.6.4/13]: Redeclarations or specializations of a function or function template with a declared return type that uses a placeholder type shall also use that placeholder, not a deduced type. [..]
By symmetry one might suggest that, in your int case, it is intended that GCC and VS be correct in rejecting the program. However, this is a different feature (since deduction cannot be applied to mere declarations) and thus a different scenario.
Either way, improved standard wording would help here. I consider it a [reasonably minor] editorial defect.
Note
I answered a question that was closed a duplicate of this one. I asked for merge and was told instead to provide an answer here. See below for my original answer.
Update clang is correct
I asked this question on twitter and the response I received from Richard Smith was as follows:
Not a defect, it's intentional that this restriction applies only to deduced return types and not to variable types. For variables, it's just a convenience shorthand, but return type deduction affects something more fundamental about functions (and especially function templates).
So the logic is that this is allowed by [dcl.spec.auto] and to restrict this for deduced return types paragraph [dcl.spec.auto]p11 was added to the section. Otherwise there is no restriction and therefore this is not restricted for the variables case.
Original
Currently [dcl.spec.auto] does not seem to cover this case explictly but it does say in [dcl.spec.auto]p5:
A program that uses auto or decltype(auto) in a context not explicitly allowed in this subclause is ill-formed.
and we can see it makes a similar case for functions ill-formed in [dcl.spec.auto]p11:
Redeclarations or specializations of a function or function template
with a declared return type that uses a placeholder type shall also
use that placeholder, not a deduced type. Similarly, redeclarations or
specializations of a function or function template with a declared
return type that does not use a placeholder type shall not use a
placeholder. [ Example:
auto f();
auto f() { return 42; } // return type is int
auto f(); // OK
int f(); // error, cannot be overloaded with auto f()
....
So although this could use clarification as currently worded it feels like gcc is correct and this is ill-formed.
I'd imagine the restriction in [dcl.spec.auto]p11 exists because otherwise, that would allow:
int f();
auto f(); // What's the return type here?
The thing is, you can have an undeduced type type has the return type of a function. There are no deduction rules based on previous declarations, which is why such mixing is disallowed for functions, even though the following would be perfectly fine:
int f();
auto f() { return 1; }
This problem does not exist for variables:
extern int v;
extern auto v; // ill-formed
Any declaration-only variables has to use a non-placeholder type. What this means is that if you use a placeholder type for the definition of v, it can get deduced without any problems and then of course has to match the non-placeholder type used in the first declaration.
extern int v;
auto v = 1; // ok, type deduced as 'int', matches first declaration.

Is this program ill-formed despite SFINAE?

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.