Return type deduction [duplicate] - c++

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Omit return type in C++11
In C++11 lambda can deduce their return type if the body consists of only a return statement. A proposal is the works to remove this restriction, and apparently it's already working in GCC.
Is there a reason this couldn't be extended to all auto returning functions?
Has this extension already been proposed?

Is there a reason this couldn't be extended to all auto returning functions?
Well, there's the fact that it wouldn't be possible unless the function was defined right there (not just a declaration). You'd lose the ability to forward declare such functions.
Also, functions don't return auto. The auto in front of a function definition is a purely syntactic thing to allow for trailing return types. And the only reason the return type is specified last is so that it can refer to the function's arguments (for template and decltype work, usually). The functions still do return a specific value.

In fact there is a reason.
Namely, the name of a function is in scope inside a function, but not in the trailing-return-type specification. Lambdas are exempt because they don't have names, although I think a variable being initialized from the lambda, typed by inference, is also in scope, so they already suffer this problem even with the standard syntax (workaround).
With the name of the function in scope, it's possible to construct an infinite circular type dependency. e.g.
auto fact(int n)
{
return (n > 0)? n*fact(n-1): 1;
}
In this case typing is consistent for several choices of return type... int, long long, float, and double, as well as std::complex<double>, etc.
No problem with trailing-return-type, the code is simply illegal:
auto fact(int n) -> decltype((n > 0)? n*fact(n-1): 1) /* unknown identifier fact */
In another example, it's inconsistent for any choice of return type:
auto f(int a)
{
char r[sizeof(f(a))+1];
return r;
}
What does your new-and-improved g++ do with this?
auto fact = [&](int n){ return (n > 0)? n*fact(n-1): 1; };

Related

Trailing return type in non-template functions [duplicate]

This question already has answers here:
Should the trailing return type syntax style become the default for new C++11 programs? [closed]
(4 answers)
Closed 2 years ago.
I have seen people using the following syntax to implement functions:
auto get_next() -> int
{
/// ...
}
Instead of:
int get_next()
{
/// ...
}
I understand both and I know that the trailing return type syntax is useful for template code using decltype. Personally I would avoid that syntax for other code since when reading code I prefer to read the concrete return type of a function first, not last.
Is there any advantage in using the trailing return type syntax for non-template code as shown above (except personal preference or style)?
In addition to sergeyrar's answer, those are the points I could imagine someone might like about trailing return types for non-template functions:
Specifying a return type for lambda expressions and functions is identical w.r.t. the syntax.
When you read a function signature left-to-right, the function parameters come first. This might make more sense, as any function will need the parameters to produce any outcome in the form of a return value.
You can use function parameter types when specifying the return type (the inverse doesn't work):
auto f(int x) -> decltype(x)
{
return x + 42;
}
That doesn't make sense in the example above, but think about long iterator type names.
One potential benefit is that it makes all of your declared function names line up:
auto get_next(int x, int y) -> int;
auto divide(double x, double y) -> double;
auto printSomething() -> void;
auto generateSubstring(const std::string &s, int start, int len) -> std::string;
source: https://www.learncpp.com/cpp-tutorial/the-auto-keyword/
Well you already mentioned the major use case of the trailing return type. It's usage if the return type depends on the arguments.
If we exclude that use case the only advantage you might gain is an enhanced readability of your code, especially if your return type is a bit more complex, but you don't have a technical benefit of using the trailing return in that scenario.

Example where trailing return type must be used, because the problem cannot be solved the old way

Is there any case, where we must use trailing return type, because the problem cannot be phrased in the old way?
auto fn() -> int; can be easily transformed to the old way: int fn();.
I wonder, is there an example, where this transformation is not possible. The most straighforward example, when we refer to function parameters in the return type, seems to be solvable by using declval.
Note: don't consider lambdas here, where we must use trailing return type.
In a trailing return type, you're allowed to apply decltype to this (see this question).
With the old syntax, you'd have to spell the class name manually... which you can't do if the class is unnamed!
(Or if the member function is generated with a macro, so the class name isn't known.)
struct
{
auto foo() -> decltype(this)
{
return this;
}
/*
decltype(this) foo() // error: invalid use of 'this' at top level
{
return this;
}
*/
} x;
I admit that this is a slightly unrealistic example, and you can easily work around it by naming the class, but I couldn't think of anything else.
One bizzare example I can think of, which needs some prerequisites.
Consider a function which cannot use auto return type deduction (e.g. it has multiple return values which cannot be deduced to the same type) and uses generic function from C++ concepts. Then you don't have a type to use for std::declval and auto deduction won't work:
auto foo(auto x)
// -> decltype(x) // comment this out to fix
{
if(x > 0) return x;
return -1; // requires int to be implicite castable to type of x
}
Demo

Why does operator() change for std::function in C++17?

The following code is supposedly illegal in C++14 but legal in C++17:
#include <functional>
int main()
{
int x = 1729;
std::function<void (int&)> f(
[](int& r) { return ++r; });
f(x);
}
Don't bother testing it, you'll get inconsistent results making it difficult to suss whether it's a bug or intentional behavior. However, comparing two drafts (N4140 vs N4527, both can be found on github.com/cplusplus/draft), there's one significant difference in [func.wrap.func.inv]. Paragraph 2:
Returns: Nothing if R is void, otherwise the return value of INVOKE (f, std::forward(args)..., R).
The above was removed between drafts. The implication is that the return value of the lambda is now silently discarded. This seems like a misfeature. Can anyone explain the reasoning?
There was a ridiculous defect in the standard about std::function<void(Args...)>. By the wording of the standard, no (non-trivial)1 use of std::function<void(Args...)> was legal, because nothing can be "implicitly converted to" void (not even void).
void foo() {} std::function<void()> f = foo; was not legal in C++14. Oops.
Some compilers took the bad wording that made std::function<void(Args...)> completely useless, and applied the logic only to passed-in callables where the return value was not void. Then they concluded it was illegal to pass a function returning int to std::function<void(Args...)> (or any other non-void type). They did not take it to the logical end and ban functions returning void as well (the std::function requirements make no special case for signatures that match exactly: the same logic applies.)
Other compilers just ignored the bad wording in the void return type case.
The defect was basically that the return type of the invocation expression has to be implicitly convertible-to the return type of the std::function's signature (see link above for more details). And under the standard, void cannot be implicitly converted to void2.
So the defect was resolved. std::function<void(Args...)> now accepts anything that can be invoked with Args..., and discards the return value, as many existing compilers implemented. I presume this is because (A) the restriction was not ever intended by the language designers, or (B) having a way for a std::function that discards return values was desired.
std::function has never required exact match of arguments or return values, just compatibility. If the incoming arguments can implicitly convert-from the signature arguments, and the return type can implicitly convert-to the return type, it was happy.
And a function of type int(int&) is, under many intuitive definitions, compatible with the signature void(int&), in that you can run it in a "void context".
1 Basically, anything that makes operator() legal to call was not allowed. You can create it, you can destroy it, you can test it (and know it is empty). You cannot give it a function, even one that matches its signature exactly, or a function object or lambda. Ridiculous.
2 For void to be impliclty converted to void under the standard, it requires that the statement void x = blah;, where blah is an expression of type void, be valid; that statement is not valid, as you cannot create a variable of type void.

Recursive call in lambda (C++11) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Recursive lambda functions in c++0x
Why can't I call a lambda recursively if I write it as:
auto a = [&]
{
static int i = 0; i++;
std::cout << i << std::endl;
if (i<10)
a(); //recursive call
};
It gives compilation error (ideone):
prog.cpp:8:18: error: '((const main()::<lambda()>*)this)->main()::<lambda()>::a' cannot be used as a function
prog.cpp: In function 'int main()':
prog.cpp:9:9: error: variable 'auto a' with 'auto' type used in its own initializer
What does the error mean?
I understand the reason why I can't write this:
auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'
We can't write this because the type of i has to be deduced from it's initialization, which means the type cannot be deduced if i itself appears in the initialization (ideone). But how does it matter in case of lambda? If I'm not wrong, the type of a lambda is determined by it's parameter(s) and the return type; it doesn't depend on the body if it returns nothing (in which case, the return type is deduced as void, irrespective of other statements in the lambda-body).
Anyway, I got a workaround, and I can use std::function instead as:
std::function<void()> a = [&]
{
static int i = 0; i++;
std::cout << i << std::endl;
if (i<10)
a();
};
which compile fines (ideone). But I'm still interested to know the reason why the auto version doesn't compile.
The reason is that there is no special case for lambda-expression initializers of auto variables.
Such special cases would be prone to errors and misuses. You need to define the rules when you propose that something like a() should work. How is the operator() looked up? What is the precise state of a's type? Will the type be complete? (which implies that you already know the capture list of the lambda). Once you have formulated that in a format reasonable for a spec, it would be easier to make statements on it.
Allowing your use case would mean yet another case where you need to scan ahead in code, because to determine the type of a in a() you must be sure that the initializer ends with nothing that could "unlambda" the type
struct y { void operator()() { } };
template<typename T> y operator+(T, y) { return y(); }
auto x = [] { x(); } + y();
In this case, x() would call y::operator(), not the lambda.
As it is now, a is simply forbidden to be mentioned in its entire initializer. Because in C++, auto is not a type. It is merely a type specifier standing for a to-be-deduced type. As a consequence, an expression can never have type auto.
As I see it the important difference between the auto a case and the std::function<void()> a case is that the type std::function<void()> doesn't know/care about what the type of the real function it refers to really is. Writing:
std::function<void()> a;
is perfectly fine, where as:
auto a;
makes little sense. So when the time comes to synthesize the capture if you use std::function<void()> all that needs to be known about the type is already known, whereas with auto it's not yet known.
In a recursive function f is defined by f and return type of f is also determined by f in case of auto so it leads to infinite recursion.
when auto tries to derive a type. decltype(f()) will further deduce to another decltype(f)` as f derives to f e.g. a call on anything recursive is recursive too. return type determination turns recursive when applied on a recursive function. in a recursive function end of the recursion may be done on runtime. but determination is static only

C++ auto keyword. Why is it magic?

From all the material I used to learn C++, auto has always been a weird storage duration specifier that didn't serve any purpose. But just recently, I encountered code that used it as a type name in and of itself. Out of curiosity I tried it, and it assumes the type of whatever I happen to assign to it!
Suddenly STL iterators and, well, anything at all that uses templates is 10 fold easier to write. It feels like I'm using a 'fun' language like Python.
Where has this keyword been my whole life? Will you dash my dreams by saying it's exclusive to visual studio or not portable?
auto was a keyword that C++ "inherited" from C that had been there nearly forever, but virtually never used because there were only two possible conditions: either it wasn't allowed, or else it was assumed by default.
The use of auto to mean a deduced type was new with C++11.
At the same time, auto x = initializer deduces the type of x from the type of initializer the same way as template type deduction works for function templates. Consider a function template like this:
template<class T>
int whatever(T t) {
// point A
};
At point A, a type has been assigned to T based on the value passed for the parameter to whatever. When you do auto x = initializer;, the same type deduction is used to determine the type for x from the type of initializer that's used to initialize it.
This means that most of the type deduction mechanics a compiler needs to implement auto were already present and used for templates on any compiler that even sort of attempted to implement C++98/03. As such, adding support for auto was apparently fairly easy for essentially all the compiler teams--it was added quite quickly, and there seem to have been few bugs related to it either.
When this answer was originally written (in 2011, before the ink was dry on the C++ 11 standard) auto was already quite portable. Nowadays, it's thoroughly portable among all the mainstream compilers. The only obvious reasons to avoid it would be if you need to write code that's compatible with a C compiler, or you have a specific need to target some niche compiler that you know doesn't support it (e.g., a few people still write code for MS-DOS using compilers from Borland, Watcom, etc., that haven't seen significant upgrades in decades). If you're using a reasonably current version of any of the mainstream compilers, there's no reason to avoid it at all though.
More recent revisions of the standard have added a few new places that auto can be used. Starting with C++14, you can use auto for the type of a parameter to a lambda:
[](auto s) { return s + 1; }
This does essentially the same thing as the example above--even though it doesn't explicitly use template syntax, this is basically a template that deduces the type of the parameter, and instantiates the template over that type.
That was convenient and useful enough that in C++20, the same capability was added for normal functions, not just lambdas.
But, just as before all of this really comes down to using the same basic type deduction mechanism as we've had for function templates since C++98. auto allows that to be used in more places, and more conveniently, but the underlying heavy lifting remains the same.
It's just taking a generally useless keyword and giving it a new, better functionality. It's standard in C++11, and most C++ compilers with even some C++11 support will support it.
For variables, specifies that the type of the variable that is being declared will be automatically deduced from its initializer. For functions, specifies that the return type is a trailing return type or will be deduced from its return statements (since C++14).
Syntax
auto variable initializer (1) (since C++11)
auto function -> return type (2) (since C++11)
auto function (3) (since C++14)
decltype(auto) variable initializer (4) (since C++14)
decltype(auto) function (5) (since C++14)
auto :: (6) (concepts TS)
cv(optional) auto ref(optional) parameter (7) (since C++14)
Explanation
When declaring variables in block scope, in namespace scope, in initialization statements of for loops, etc., the keyword auto may be used as the type specifier.
Once the type of the initializer has been determined, the compiler determines the type that will replace the keyword auto using the rules for template argument deduction from a function call (see template argument deduction#Other contexts for details). The keyword auto may be accompanied by modifiers, such as const or &, which will participate in the type deduction. For example, given const auto& i = expr;, the type of i is exactly the type of the argument u in an imaginary template template<class U> void f(const U& u) if the function call f(expr) was compiled. Therefore, auto&& may be deduced either as an lvalue reference or rvalue reference according to the initializer, which is used in range-based for loop.
If auto is used to declare multiple variables, the deduced types must match. For example, the declaration auto i = 0, d = 0.0; is ill-formed, while the declaration auto i = 0, *p = &i; is well-formed and the auto is deduced as int.
In a function declaration that uses the trailing return type syntax, the keyword auto does not perform automatic type detection. It only serves as a part of the syntax.
In a function declaration that does not use the trailing return type syntax, the keyword auto indicates that the return type will be deduced from the operand of its return statement using the rules for template argument deduction.
If the declared type of the variable is decltype(auto), the keyword auto is replaced with the expression (or expression list) of its initializer, and the actual type is deduced using the rules for decltype.
If the return type of the function is declared decltype(auto), the keyword auto is replaced with the operand of its return statement, and the actual return type is deduced using the rules for decltype.
A nested-name-specifier of the form auto:: is a placeholder that is replaced by a class or enumeration type following the rules for constrained type placeholder deduction.
A parameter declaration in a lambda expression. (since C++14) A function parameter declaration. (concepts TS)
Notes
Until C++11, auto had the semantic of a storage duration specifier.
Mixing auto variables and functions in one declaration, as in auto f() -> int, i = 0; is not allowed.
For more info : http://en.cppreference.com/w/cpp/language/auto
This functionality hasn't been there your whole life. It's been supported in Visual Studio since the 2010 version. It's a new C++11 feature, so it's not exclusive to Visual Studio and is/will be portable. Most compilers support it already.
The auto keyword is an important and frequently used keyword for C ++.When initializing a variable, auto keyword is used for type inference(also called type deduction).
There are 3 different rules regarding the auto keyword.
First Rule
auto x = expr; ----> No pointer or reference, only variable name. In this case, const and reference are ignored.
int y = 10;
int& r = y;
auto x = r; // The type of variable x is int. (Reference Ignored)
const int y = 10;
auto x = y; // The type of variable x is int. (Const Ignored)
int y = 10;
const int& r = y;
auto x = r; // The type of variable x is int. (Both const and reference Ignored)
const int a[10] = {};
auto x = a; // x is const int *. (Array to pointer conversion)
Note : When the name defined by auto is given a value with the name of a function,
the type inference will be done as a function pointer.
Second Rule
auto& y = expr; or auto* y = expr; ----> Reference or pointer after auto keyword.
Warning : const is not ignored in this rule !!! .
int y = 10;
auto& x = y; // The type of variable x is int&.
Warning : In this rule, array to pointer conversion (array decay) does not occur !!!.
auto& x = "hello"; // The type of variable x is const char [6].
static int x = 10;
auto y = x; // The variable y is not static.Because the static keyword is not a type. specifier
// The type of variable x is int.
Third Rule
auto&& z = expr; ----> This is not a Rvalue reference.
Warning : If the type inference is in question and the && token is used, the names
introduced like this are called "Forwarding Reference" (also called Universal Reference).
auto&& r1 = x; // The type of variable r1 is int&.Because x is Lvalue expression.
auto&& r2 = x+y; // The type of variable r2 is int&&.Because x+y is PRvalue expression.
The auto keyword specifies that the type of the variable that is being declared will be automatically deducted from its initializer. In case of functions, if their return type is auto then that will be evaluated by return type expression at runtime.
It can be very useful when we have to use the iterator. For e.g. for below code we can simply use the "auto" instead of writing the whole iterator syntax .
int main()
{
// Initialize set
set<int> s;
s.insert(1);
s.insert(4);
s.insert(2);
s.insert(5);
s.insert(3);
// iterator pointing to
// position where 2 is
auto pos = s.find(3);
// prints the set elements
cout << "The set elements after 3 are: ";
for (auto it = pos; it != s.end(); it++)
cout << *it << " ";
return 0;
}
This is how we can use "auto" keyword
It's not going anywhere ... it's a new standard C++ feature in the implementation of C++11. That being said, while it's a wonderful tool for simplifying object declarations as well as cleaning up the syntax for certain call-paradigms (i.e., range-based for-loops), don't over-use/abuse it :-)
It's Magic is it's ability to reduce having to write code for every Variable Type passed into specific functions. Consider a Python similar print() function in it's C base.
#include <iostream>
#include <string>
#include <array>
using namespace std;
void print(auto arg) {
cout<<arg<<" ";
}
int main()
{
string f = "String";//tok assigned
int x = 998;
double a = 4.785;
string b = "C++ Auto !";
//In an opt-code ASCII token stream would be iterated from tok's as:
print(a);
print(b);
print(x);
print(f);
}