class A {
public:
int a;
char b;
double c;
A ( int x, char y, double z ) : a(x), b(y), c(z){}
};
int main(){
auto lambda = []( auto x ) {
static auto y = x;
// y = x;
return y;
};
int a = lambda(1);
char b = lambda('a');
double c = lambda(1.5);
A d = lambda( A( 2, 'b', 2.5 ) );
return 0;
}
This code compiles in Clang 3.8.0 and GCC 5.4.0, and works fine. However, taking into account that variable y is static:
What is the type of variable y? Does the type of y change in every call to the lambda?
Is variable y initialized in every call in spite of being static? The commented assignment // y = x is not needed to update the value of variable y.
Is this behaviour C++14 Standard compliant?
If I print the sizeof(y) in each call I get 4, 1, 8 and 16 respectively.
On local and global static variables in C++
Your lambda is generic. Which means that this is a template in disguise. The situation is handled in accordance with general rules for template specializations.
For every specific deduced type of parameter x you get a separate specialization of your function. So, yes for each specific type of x you get a separate copy of y. But the underlying mechanism is not somehow localized at your static, it is the whole body of your function that gets "copied" to produce a separate independent implementation of the function.
Each specialization of your lambda will have a separate copy of y, which will be initialized only once at the first call to that specific specialization.
The situation is virtually equivalent to a more explicit
template <typename T> void foo(T x)
{
static T y = x;
std::cout << y << std::endl;
}
int main()
{
foo(1);
foo('a');
foo(1.5);
foo(3.0);
}
which outputs 1, a, 1.5 and 1.5.
In this example you get three independent specializations of foo: foo<int>, foo<char> and foo<double>. Each version of foo gets its own version of y, meaning that there are three different static ys in this example. The first call to each specialization will initialize y and the subsequent calls will not re-initialize it. In this case call to foo(1.5) initializes y for foo<double>, but the subsequent call to foo(3.0) does not.
The same thing happens in your case as well, it just uses a different syntax.
Lamda with auto is nothing more than a class with operator () overloaded to be a template and using auto for type deduction (which follows the rules for a template parameter deduction).
In this case you have as many static y fields as many instantiations of this function object template operator.
The initialization is done like in hand written class which is the first time the function is triggered (the lambda in this case)
Related
It is necessary for me to use std::function but I don't know what the following syntax means.
std::function<void()> f_name = []() { FNAME(); };
What is the goal of using std::function? Is it to make a pointer to a function?
std::function is a type erasure object. That means it erases the details of how some operations happen, and provides a uniform run time interface to them. For std::function, the primary1 operations are copy/move, destruction, and 'invocation' with operator() -- the 'function like call operator'.
In less abstruse English, it means that std::function can contain almost any object that acts like a function pointer in how you call it.
The signature it supports goes inside the angle brackets: std::function<void()> takes zero arguments and returns nothing. std::function< double( int, int ) > takes two int arguments and returns double. In general, std::function supports storing any function-like object whose arguments can be converted-from its argument list, and whose return value can be converted-to its return value.
It is important to know that std::function and lambdas are different, if compatible, beasts.
The next part of the line is a lambda. This is new syntax in C++11 to add the ability to write simple function-like objects -- objects that can be invoked with (). Such objects can be type erased and stored in a std::function at the cost of some run time overhead.
[](){ code } in particular is a really simple lambda. It corresponds to this:
struct some_anonymous_type {
some_anonymous_type() {}
void operator()const{
code
}
};
an instance of the above simple pseudo-function type. An actual class like the above is "invented" by the compiler, with an implementation defined unique name (often including symbols that no user-defined type can contain) (I do not know if it is possible that you can follow the standard without inventing such a class, but every compiler I know of actually creates the class).
The full lambda syntax looks like:
[ capture_list ]( argument_list )
-> return_type optional_mutable
{
code
}
But many parts can be omitted or left empty. The capture_list corresponds to both the constructor of the resulting anonymous type and its member variables, the argument_list the arguments of the operator(), and the return type the return type. The constructor of the lambda instance is also magically called when the instance is created with the capture_list.
[ capture_list ]( argument_list ) -> return_type { code }
basically becomes
struct some_anonymous_type {
// capture_list turned into member variables
some_anonymous_type( /* capture_list turned into arguments */ ):
/* member variables initialized */
{}
return_type operator()( argument_list ) const {
code
}
};
Note that in c++20 template arguments were added to lambdas, and that isn't covered above.
[]<typename T>( std::vector<T> const& v ) { return v.size(); }
1 In addition, RTTI is stored (typeid), and the cast-back-to-original-type operation is included.
Let's break the line apart:
std::function
This is a declaration for a function taking no parameters, and returning no value. If the function returned an int, it would look like this:
std::function<int()>
Likewise, if it took an int parameter as well:
std::function<int(int)>
I suspect your main confusion is the next part.
[]() { FNAME(); };
The [] part is called a capture clause. Here you put variables that are local to the declaration of your lambda, and that you want to be available within the lambda function itself. This is saying "I don't want anything to be captured". If this was within a class definition and you wanted the class to be available to the lambda, you might do:
[this]() { FNAME(); };
The next part, is the parameters being passed to the lambda, exactly the same as if it was a regular function. As mentioned earlier, std::function<void()> is a signature pointing to a method that takes no parameters, so this is empty also.
The rest of it is the body of the lambda itself, as if it was a regular function, which we can see just calls the function FNAME.
Another Example
Let's say you had the following signature, that is for something that can sum two numbers.
std::function<int(int, int)> sumFunc;
We could now declare a lambda thusly:
sumFunc = [](int a, int b) { return a + b; };
Not sure if you're using MSVC, but here's a link anyway to the lamda expression syntax:
http://msdn.microsoft.com/en-us/library/dd293603.aspx
Lambdas with captures (stateful lambdas) cannot be assigned to each other since they have unique types, even if they look exactly the same.
To be able to store and pass around lambdas with captures, we can use "std::function" to hold a function object constructed by a lambda expression.
Basically "std::function" is, to be able to assign lambda functions with different content structures to a lambda function object.
Exp :
auto func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //ATTENTION(ERROR!): assigning a new structure to the same object
cout << "x:" << x << ",a:" << a << endl;
};
func(2);
So the above usage will be incorrect.
But if we define a function object with "std::function":
auto func = std::function<void(int)>{};
func = [](int a){
cout << "a:" << a << endl;
};
func(40);
//
int x = 10;
func = [x](int a){ //CORRECT. because of std::function
//...
};
int y = 11;
func = [x,y](int a){ //CORRECT
//...
};
Here is a simple example (the idea is to avoid a huge if..else or switch block inside a function):
namespace foo {
enum class VALUES : int { val_0 = 0, val_1 = 1 };
template<VALUES T>
void print();
template<>
void print<VALUES::val_0>() { std::cout << "val_0\n"; }
template<>
void print<VALUES::val_1>() { std::cout << "val_1\n"; }
void bar(int type) {
VALUES v = static_cast<VALUES>(type);
print<v>(); //error C2971 - "v" is a non-constant argument at compile-time
}
};
The question is how to call print<...>() based on the bar's parameter?
Please do not suggest to use if..else or switch.
Templates are deduced at compile time. Which means that those template arguments are constant (at compile time). In your case, int type is not a constant type and so is VALUES v. In order to resolve v at compile time, you need to mark is as constexpr VALUES v; and which also means that you need to initialize it with values. In this case, with compile time resolvable values. That's why this works,
constexpr VALUES v = VALUES::val_0;
print<v>();
But not this,
VALUES m = VALUES::val_0;
constexpr VALUES v = m; // As soon as you do this, it is no longer resolvable at compile time.
print<v>();
So the simplest answer is, you will have to use if/else, switch or templates to get it done.
Here is a way to do so: https://stackoverflow.com/a/66171400/15104979
we just need a storage for all those functions and also they can be not templated. Also for non-members the Callback can be defined like using Callback = void(*)();. But we have to measure both cases: with if/else and Callback, specifically for your case.
I have this small piece of code that doesn't compile, and I was wondering about the reasons more specifically why is push(new X) the problem?
Before that, I would like to ask what new X (with no identifier) really mean? does it create an object X with no identifier name? does it go through the constructor at all?
Secondly,
I might not understand the whole concept, but, push is a template class, right?
Since it contains a static T stack, the type T is consistent and can not be changed once a specific argument is sent, the first one, in this case int x. Is that correct?
Thirdly,
following my second question, if it is correct then why push(y) do not flag a compiler error just like push(new X) does? i mean, x is an int type and y is a reference type.
I'd really appreciates if someone can clarify it for me.
Thanks, here it is:
#include <iostream>
using namespace std;
template <class T>
void push(T &t) {
static const int CAPACITY = 20;
static T stack[CAPACITY];
static int size = 0;
stack[size++] = t;
cout << size;
};
class X {};
void main()
{
int x = 3;
int &y = x;
push(x);
push(new X);
push(y);
}
and I was wondering about the reasons more specifically why is push(new X) the problem?
Because you declared type of your template function parameter as non const lvalue reference to T. To help programmers to avoid incorrect code language does not allow to bind temporaries to non const lvalue references. In your case:
new X
returns a temporary of type X * (pointer to X), your template function argument type T deduced to X * in this case and t is now lvalue reference to X * or X *& but language does not allow to bind temporary to an lvalue reference hense compilation error. Your second case is logically equal to this code:
void pushX( X *&t ); // pushX accepts reference to pointer to X
pushX( new X ); // you cannot bind a temporary returned by `new X` to lvalue reference `t`
It could be easier to understand if you use simple type like int:
int function_returns_int();
void push_int( int &ri );
push_int( function_returns_int() ); // compilation error, function_returns_int() returns temporary
You can make your code compile if you store pointer in a variable and make it non-temporary:
int main() // main() must have return type int not void
{
int x = 3;
int &y = x;
push(x);
X *px = new X;
push(px);
push(y);
delete px;
}
but most probably you chosen wrong type for the argument.
Details about references and why you can pass int &y and why t would not be a reference to reference in this case you can find here
Note: your code if you make it compile (changing type of t to const reference for example) would lead to memory leak, but that is out of scope of your question
The most recent draft of the structured bindings proposal (on which the C++17 feature was based) requires std::tuple_size, member get or std::get, and std::tuple_element. Previous drafts require only std::tuple_size and member get or std::get. As far as I can tell, there was no discussion on adding this, it just appeared in the final draft. Is there a compelling reason to require the tuple_element specialization, considering I believe it can be implemented in general as
template<std::size_t index, typename T>
struct tuple_element {
using type = decltype(std::get<index>(std::declval<T>()));
};
Does anyone know of why this requirement was added?
Consider the case:
std::tuple<int, int&>& foo();
auto& [x, y] = foo();
What is decltype(x) and what is decltype(y)? The goal of the language feature is that x just be another name for foo().__0 and y be another name for foo().__1, which means that they should to be int and int&, respectively. As specificied today, this unpacks into†:
auto& __e = foo();
std::tuple_element_t<0, decltype(__e)>& x = std::get<0>(__e);
std::tuple_element_t<1, decltype(__e)>& y = std::get<1>(__e);
And the rules work such that decltype(x) is the type to which x refers, so int. And decltype(y) is the type to which y refers, so int&.
If we avoided tuple_element, by doing something like:
auto&& x = std::get<0>(__e);
auto&& y = std::get<1>(__e);
Then we couldn't differentiate between x and y, because there is no way to differentiate between what std::get<0>(__e) and std::get<1>(__e) do: both give back an int&.
This is also the way to add consistency between the above case and the normal struct case:
struct C {
int i;
int& r;
};
C& bar();
auto& [a, b] = bar();
We want, for the purposes of structured bindings, for a and b here to behave the same way as x and y there. And a and b here aren't introduced variables, they're just different names for __e.i and __e.r.
In the non-reference case, there is a different scenario where we cannot differentiate:
std::tuple<int, int&&> foo();
auto [x, y] = foo();
Here, we at present unpack via:
auto __e = foo();
std::tuple_element_t<0, decltype(e)>& x = std::get<0>(std::move(__e));
std::tuple_element_t<1, decltype(e)>& y = std::get<1>(std::move(__e));
Both std::get calls return an int&&, so you couldn't differentiate between them using auto&&... but the results of tuple_element_t are different - int and int&&, respectively. This difference could be seen with the normal struct case too.
†Note that due to CWG 2313, actually the unpacking happens into a uniquely named variable reference and the identifiers specified into the binding just refer to those objects.
I had a Q&A before: Point of declaration in C++. The rule point-of-declaration nicely is applicable on many situations. Now, I confused on usage of auto in combination of this rule.
Consider these two codes:
i. Declaring x by itself (we don't expect it to work):
{
auto x = x;
}
ii. Declaring the inner x by the outer x (It makes error in gcc 4.8.x):
{
int x = 101; // the outer x
{
auto x = x; // the inner x
}
}
According to the rule of point-of-declaration, it should work but it doesn't. It seems there is another rule in the standard that I missed it. The question is, Where is the point-of-declaration when using auto?
There are two possibilities:
i. If the point of declaration is after =, at the end of statement:
auto object = expression;
^
Is it here? If it is, why gcc complains?
So the second declaration is valid and must work, because there is no x but that outer one (which is declared before). Therefore auto x=x is valid and the inner x should be assigned to 101.
ii. If the point of declaration is before = :
auto object = expression;
^
Well, it doesn't make any sense because auto has to wait until see the following expression. For example auto x; is invalid.
Update: I need an answer which explains it by the rule point of declaration.
auto x = x; // inner x
is ill-formed.
To quote from the C++11 standard (emphasis mine):
7.1.6.4 auto specifier
...
3 Otherwise, the type of the variable is deduced from its initializer. The name of the variable being declared
shall not appear in the initializer expression. ...
And so because x after = resolves to the x in auto x (as explained in the question you linked), that above piece of code is ill-formed.
Just like in any other kind of definition, the x on the right-hand side of the initialiser for auto x = x resolves to the local auto x. C++ has always done this (i.e. int x = x compiles but will give you undefined behaviour).
The reason auto x = x fails to compile is because while x is in scope it has no known type yet, and so using it as the initialiser fails because the type can't be deduced from the expression.
Just like any other kind of declaration, x is in scope after its declarator which is auto x.
int x = 10;
int y = 20;
{
int x = x; // This is NOT the outer x. This is undefined behaviour (reading an
// uninitialised variable).
auto y = y; // This is NOT the outer y. This is a compile error because the type of
// y is not known.
}
Just adding an example with more explicit diagnostics:
auto ll = [&] { ll(); };
Results in (gcc):
error: variable ‘auto ll’ with ‘auto’ type used in its own initializer
or (clang):
error: variable 'll' declared with 'auto' type cannot appear in its own initializer
auto ll = [&] { ll(); };
^
You can see that there is an explicit rule for this. I haven't looked at the specs.
The compiler reads a whole statement (from the beginning of a line until the next semi-colon) and then evaluates the different parts of a statement using priorities of operations, and then when the time comes when the value of auto x is to be assigned, the type that came up after th = sign gets taken.
For example:
template <typename T>
T sum(T a, T b)
{
return a+b;
}
int main()
{
auto x = sum<double>(1,5); // x here is a double, because the return value is double
auto y = sum<int>(1,7); //y is an int, because the return value is int
}
And about your auto x = x, you're redefining the same variable name. That's invalid! auto y = x shall work.