What is the point of using compilation characteristics of uncaught local variables in lambda?

I noticed that you can use compilation time parameters for variables that were not written to lambda, for example. call sizeof , decltype , for example:

 #include <iostream> void f () { } int main() { int y = 13; auto x = []{ return sizeof (decltype (y));}; std::cout << x () << '\n'; } 

Like g++ and clang++ compile this program without errors, I assume that this is allowed by the standard.

This seems to be a bit misleading to me, although I cannot come up with any specific malicious case where this will lead to an error. But I wonder what are the actual use cases for this feature?

+6
source share
2 answers

A simple example where you can use this is that you have a lambda where you want to perform calculations in the same type as y , because you assign the result to y .

Also, think about it differently: what is the use of capturing y in [=]{ return x + sizeof (y);} ? There is absolutely no point in this, since y is not actually used inside lambda. Capturing y will simply add completely pointless overhead. Not only can this complicate the internal work of compilers, since they can no longer simply optimize y , sizeof(y) no longer semantically equivalent to sizeof(int) .

+5
source

Sometimes in a nested area (lambda) you need type information without a value. You can always specify the type (or template parameter) directly if you have access to it, but there is always a good Soviet letter saying that if you ever change the type of a variable, you won’t have to change it in all other expressions in which you repeated it.

For instance:

 #include <iostream> #include <tuple> #include <utility> class storage { public: template<typename T> auto make_getter(T value) { std::get<decltype(value)>(storage_) = value; auto getter = [this] { return std::get<decltype(value)>(storage_); }; return getter; } private: std::tuple<int, char, double> storage_; }; int main(void) { storage s; auto getter = s.make_getter(42); std::cout << getter() << std::endl; } 

Here you can always use std::get<T> instead of std::get<decltype(value)> , but if someday make_getter no longer a template and becomes a normal function, overloaded for each type of tuple, than the type of value would change to int For example, the advantage is that decltype(value) will always work unless you rename the variable.

In any case, I think that the utility level of this function may be more semantic than technical. This behavior is probably inherited from the old canonical school

 char *buffer = malloc(42 * sizeof(*buffer)); 

used in C instead

 char *buffer = malloc(42 *sizeof(char)); 

for the same reasons.

Also, if the type name is something unbearable because of which you do not want to use an alias for any reason, you will go the decltype path, which does not necessarily mean that you want a bound value.

0
source

Source: https://habr.com/ru/post/988585/


All Articles