I understand that using templates is one of the appreciated way of overloading but i was wondering why auto cannot be used for function parameter type deduction hence aiding overloading of the function?
N3690 says in 7.6.1.4/3 that lambda expression can be made generic using auto,providing this example
auto glambda = [](int i, auto a) { return i; };//OK: a generic lambda
(note: this is not mentioned in N3485)
1).why cant i do a similar thing for a normal function for e.g
void swap(auto& param1, decltype(param1)& param2)
{
decltype(param1) temp = param1;
param1 = param2;
param2 = temp;
}
this gives errors error : parameters declared auto.
from N3690 7.1.6.4/4
The type of a variable declared using auto or decltype(auto) is deduced from its
initializer. This use is allowed when declaring variables in a block (6.3), in namespace scope (3.3.6), and in a for-init-statement (6.5.3).[...]
am i wrong in assuming that the param1 and param2 fall under block scope and hence eligible for auto deduction?
2). if such feature was allowed what would be the pitfalls?
i'm using gcc 4.8.1.
Thank you
n3690 7.1.6.4/2
The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq,
conversion-function-id, or trailing-return-type, in any context where such a declarator is valid.
7.1.6.4/3
If the auto type-specifier appears as one of the decl-specifiers in the decl-specifier-seq of a parameter-
declaration of a lambda-expression, the lambda is a generic lambda.
7.1.6.4/4
The type of a variable declared using auto or decltype(auto) is deduced from its initializer. This use is al-
lowed when declaring variables in a block (6.3), in namespace scope (3.3.6), and in a for-init-statement (6.5.3).
auto or decltype(auto) shall appear as one of the decl-specifiers in the decl-specifier-seq and the decl-
specifier-seq shall be followed by one or more init-declarators, each of which shall have a non-empty initial-
izer.
7.1.6.4/5
A placeholder type can also be used in declaring a variable in the condition of a selection statement (6.4) or
an iteration statement (6.5), in the type-specifier-seq in the new-type-id or type-id of a new-expression (5.3.4), in
a for-range-declaration, and in declaring a static data member with a brace-or-equal-initializer that appears
within the member-specification of a class definition (9.4.2).
Only such usage is alowed. Any other usage is prohibited (in particular usage in parameter-declaration-clause).
7.1.6.4/6
A program that uses auto or decltype(auto) in a context not explicitly allowed in this section is ill-formed.
N3690 is the committee draft for C++14, i.e. for the next C++ standard that has yet to be released and wich might not be implemented yet in most compilers. So you should refer to your compiler's documentation if generic lambdas are implemented - I guess they are not.
However, with gcc you have good chances that C++14 features will be implemented before the new standard is officially released, though you might have to explicitly enable C++14 support with a command line flag. Looking at the docs it should be -std=gnu++1y
According to this site, generic lambdas are not implemented yet in GCC.
Update:
As for normal generic functions using auto parameters: These don't exist and won't be coming for the next time. The reason is that templated functions are only slightly more verbose to type and more powerful, since you can refer to the types and directly apply template metafunctions to them. In generic lambdas this can be done only by using decltype(a), wich is a bit more tedious and has to be used with care, because it behaves a bit different than template argument deduction.
An additional bonus with templates compared to auto params is a bit more typesafety or expressiveness:
void func(auto a, auto b); //a and b might be different types
template <class T>
void func(T a, T b); //a and b must be the same type
On top of ForEveR's answer:
Why cant i do a similar thing for a normal function for e.g
void swap(auto& param1, decltype(param1)& param2)
Simply because the language doesn't allow this. Before auto was (re)invented in C++11 what you want was achievable through templates:
template <class T, class U>
void swap(T& param1, U& param2);
C++11 also brough lambda expressions and C++14 is likely to introduce polymorphic lambdas which are, basically, lambdas whose operator () are templates. A syntax similar to that of templates was considered for the polymorphic lambdas, for instance (example taken from N3418)
[]<class T>(T* p) { /* ... */ }
At the end, the prefered syntax was using auto rather than introducing a template parameter list.
It's true that one could consider extend this terser syntax to function templates (as the OP suggests) but, as far as I know, the committee hasn't considered this possibility. It might do in the future but someone has to formally propose it. This might be a "nice feature to have" but IMHO this is just syntactic sugar that doesn't bring much to the language.
Also, I can't see how this terser syntax (with no template parameter lists) could be used for template classes and perhaps diverging the syntax for template functions from that of template classes is not worth doing.
There is already a way to write what you wanted :-
template <class T>
void swap(T& param1, T& param2)
{
T temp = param1;
param1 = param2;
param2 = temp;
}
So why create a new syntax that doesn't let you do anything you couldn't do before. The suggested change to lambdas are to allow generic lambdas which you couldn't do before, and I guess any syntax using the template syntax would have been ugly here.
Related
Auto keyword is used to infer the type of the variable based on the initialization. But I read on internet that auto can't determine the type of the function parameters. I didn't understand the reason why auto can't determine the type when used with function parameters. Can any one please let me know why auto can't be used with function parameters and any other cases where auto keyword can't be used to determine the type.
"Can't" is a strong word. After all, lambda parameters can use auto (in C++14). It's not so much "can't" as "doesn't". And perhaps "won't".
The question ultimately comes down to this: what does this actually do?
void foo(auto x)
{
std::cout << x << std::endl;
}
auto deduction is ultimately based on providing an initializing expression, which is used to deduce the actual type. This declaration contains no initializing expression.
C++ is a statically typed language; that means the compiler must be able to determine the type of every expression and object at compile time. From just the above, the compiler can deduce nothing.
So how can the compiler know that std::cout << x is legal C++ syntax? It can only tell that if there is an operator<< overload that takes std::cout and x. It can't figure out what is being called without first knowing the type of x. Which it doesn't; it can be different for different invocations of the function.
However, there is one C++ construct where the above makes sense: a template. This is exactly what using auto in lambda parameters does; it implicitly transforms the function into a template function. So [](auto x) {return x;} effectively becomes an operator something like this:
template<typename T>
auto operator()(T x) {return x;}
However, this conversion doesn't just fall out of having auto as a deduction syntax. It has to be something the standard is explicitly written to require. And, with the exception of C++14 generic lambdas, it doesn't.
Concepts TS includes this facility. However, this is merely an extension of the ability to use concepts in function parameter lists at all. That is, they already have a way to make a function implicitly create a template function, so they just added auto as essentially a case of "a concept that accepts any type".
But this was explicitly excluded from the C++20 version of concepts. The general reason for this exclusion is that, up until this point, template functions could be detected because they always had to have some special syntax. Namely, the inducer template<args>. With the Concepts TS version, there is concern that people will write template functions without realizing it.
And template functions behave differently from non-template functions. A template function is a family of functions, so you can't get a pointer to the family itself. You'd have to explicitly instantiate the template to get a pointer to that particular function.
As far as I understand - generic lambdas are transformed into objects of local scope structs with templated operator(). This makes generic lambda very powerful and easy to use tool. On the other hand one can create structs nested into the function, when however the struct has templated member e.g.:
#include <iostream>
int main() {
struct inner {
template <class T>
void operator()(T &&i) { }
};
return 0;
}
or is templated by itself:
int main() {
template <class T>
struct inner {
void operator()(T &&i) { }
};
return 0;
}
compiler seems to have a problem with compiling it:
error: invalid declaration of member template in local class
and
error: a template declaration cannot appear at block scope
I assume the problem lays more in c++ standard than in compiler bug. What are the reasons lambdas are allowed to have templated members and not the local structures?
I found this qustion, but I think the answer is kind of outdated (I don't think it's true even for c++11).
This is core issue 728, which was filed before generic lambdas were a thing.
You mentioned generic lambdas and that they were identical to local classes with corresponding member template operator(). However, they actually aren't, and the differences are related to implementation characteristics. Consider
template <typename T>
class X {
template <typename>
void foo() {
T t;
}
};
And
template <typename T>
auto bar() {
return [] (auto) {T t;};
};
Instantiating these templates with <void> will be fine in the first case, but ill-formed in the second. Why fine in the first case? foo need not be instantiatable for each particular T, but just one of them (this would be [temp.res]/(8.1)).
Why ill-formed in the second case? The generic lambda's body is instantiated - partially - using the provided template arguments. And the reason for this partial instantiation is the fact that…
…the lexical scopes used while processing a function definition are fundamentally transient, which means that delaying instantiation of some portion of a function template definition is hard to support.
(Richard Smith) We must instantiate enough of the local "template" to make it independent of the local context (which includes template parameters of the enclosing function template).
This is also related to the rationale for
[expr.prim.lambda]/13, which mandates that an entity is implicitly captured by a lambda if it…
names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
That is, if I have a lambda like [=] (auto x) {return (typename decltype(x)::type)a;}, where a is some block-scope variable from an enclosing function, regardless of whether x's member typedef is for void or not, the cast will cause a capture of a, because we must decide on this without waiting for an invocation of the lambda. For a discussion of this problem, see the original proposal on generic lambdas.
The bottom line is that completely postponing instantiation of a member template is not compatible with the model used by (at least one) major implementation(s), and since those are the expected semantics, the feature was not introduced.
Was that the original motivation for this constraint? It was introduced sometime between January and May 1994, with no paper covering it, so we can only get a rough idea of the prevailing notions from this paper's justification of why local classes shall not be template arguments:
Class templates and the classes generated from the template are global scope
entities and cannot refer to local scope entities.
Perhaps back then, one wanted to KISS.
I assume the problem lays more in c++ standard
Correct. This is stipulated in [temp] for class templates:
A template-declaration can appear only as a namespace scope or class scope declaration.
and [temp.mem] for member templates:
A local class of non-closure type shall not have member templates.
What are the reasons lambdas are allowed to have templated members and not the local structures?
Because once we had lambdas in C++11, it was deemed that it would be extremely useful to extend that concept to have generic lambdas. There was a proposal for such a language extension, which was revised and revised and adopted.
On the other hand, there has not yet been a proposal presented (as far as I'm aware from a brief search) that lays out the motivation for the need for member templates in local classes that isn't adequately solved by a generic lambda.
If you feel that this is an important problem that needs to be solved, feel free to submit a proposal after laying out a thoughtful motivation for why local member templates are important.
Does C++11 allow declaring non-static data members as 'auto' if they are initialized in the declaration? For example:
struct S
{
auto x = 5; // in place of 'int x = 5;', which is definitely allowed
};
GCC 4.7 rejects the above code, while it accepts int x = 5;.
Assuming this is not a compiler bug but rather the standard really doesn't allow it, why not? It would be just as useful as declaring local variables auto.
The rule for prohibiting non-static members is in 7.1.6.4 clause 4:
The auto type-specifier can also be used in declaring a variable in
the condition of a selection statement (6.4) or an iteration statement
(6.5), in the type-specifier-seq in the new-type-id or type-id of a
new-expression (5.3.4), in a for-range-declaration, and in declaring a
static data member with a brace-or-equal-initializer that appears within the member-specification of a class definition (9.4.2).
I found the rationale for it being static here which reflects how James McNellis explains it in the comment.
One national body dislikes allowing the auto type-specifier for
non-statics. From an e-mail to the authors:
template< class T >
struct MyType : T {
auto data = func();
static const size_t erm = sizeof(data);
};
In order to determine the layout of X, we now have 2-phase name lookup and ADL. Note that func could be either a type or a function;
it may be found in T, the namespace of MyType, the associated
namespace(s) of T when instantiated, the global namespace, an
anonymous namespace, or any namespaces subject to a using directive.
With care we could probably throw some concept_map lookup in for luck.
Depending on the order of header inclusion I might even get different results for ADL, and break the One Definition Rule - which
is not required to be diagnosed.
Because of this controversy, the authors no longer propose that auto
be allowed for non-static data members.
So, basically depending on the order of header inclusion, the type of data could be very different. Of course, auto x = 5; would not need to depend on 2-phase name lookup or ADL, however, I'm a assuming that they made it a "blanket" rule because otherwise, they would have to make individual rules for every use case which would make things very complicated.
In the same paper, the author proposes eliminating this restriction, however, it seems this proposal has been rejected probably due to the above rationale and also so that expected behavior can be the same no matter what the initializer is.
For others:
Using C++17 this is indirectly (automatic deduction of non-static member type) possible. You need to use templates and deduction guides to make it happen:
template< class data_t>
struct MyType
{
data_t data;
static constexpr auto data_size = sizeof(data_t);
MyType( data_t && p_data ) : data(p_data) {}
};
template< class data_t>
MyType(data_t &&) -> MyType<std::remove_reference_t<data_t>>;
I don't know how but this auto members really need to make it into the language without them certain patterns are next to impossible.
The scenario above does not work if the lambda captures a member of class by reference. This is a useful pattern for, highly compensable classes that avoid the use of type erased functions. Something I regularly do on embedded systems.
https://godbolt.org/z/W-K9Uk
You can mangle the language into submission allowing a lambda to reference a member of a non-existent class using placement-new and offset_of but that is ludicrous and shouldn't be required.
Later discussion was publicly summarized in 2014: the critical point was that a default member initializer is a complete-class context but the type of any member is not. One further bit of rationale is that it would be odd to have
std::vector<int> get_ints();
struct S {
auto x=get_ints();
S() : x(7,4) {}
};
use the type of the default member initializer despite completely ignoring it otherwise.
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.
I happened to come across the below code snippet in a video on C++11, where the author uses
auto main()->int
I didn't understand this. I tried to compile in g++ using -std=c++11 and it works.
Can somebody explain to me what is going on here? I tried to search using "auto main()->int" but didn't find any help.
C++11 introduced a notation for trailing return types: If a function declaration is introduced with auto, the return type will be specified after the parameters and a -> sequence. That is, all that does is to declare main() to return int.
The significance of trailing return types is primarily for function template where it is now possible to use parameters to the function together with decltype() to determine the return type. For example:
template <typename M, typename N>
auto multiply(M const& m, N const& n) -> decltype(m * n);
This declares the function multiply() to return the type produced by m * n. Putting the use of decltype() in front of multiply() would be invalid because m and n are not, yet, declared.
Although it is primarily useful for function template, the same notation can also be used for other function. With C++14 the trailing return type can even be omitted when the function is introduced with auto under some conditions.
This is a uniform function declaration syntax, trailing return type, introduced in C++11.
You can't use any other syntax for lamdas, and it's also very convenient for function templates where the result type depends on arguments.
If you want to select one single syntax (and I think that's a good idea), then you don't have any choice: the old syntax can't be used for lambdas.
Reason for doing that include:
Well, a single syntax.
Function name always at the same place visually, supports fast scanning of code.
Ditto for the result type, easy visual recognition (plus, you don't have to qualify it when it's a type defined in a member function's class).
Reasons against include some added verbosity, use of old compilers that don't understand this syntax, that anything new can feel scary and uncomfortable and just odd.
It is called trailing-return-type. It is particularly useful in generic codes using templates where the return type of depends on the expression involving some other template arguments. It is also used in lambda.
Here is an example:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t+u)
{
return t + u;
}
Here the return type depends on the expression t+u. So whatever the type of the expression, is also the return-type of the function, which is indicated by decltype(t+u).