Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Value category of const int variable captured by lambda

I have been attempting to understand when and when not a lambda with a capture-default odr-uses a variable with automatic storage duration defined in its surrounding scope (prompted by this answer). While exploring around this I came across a little curiosity. GCC and Clang appear to disagree about the value category of the id-expression n in the following code:

template <typename T> void assert_is_lvalue(const T&) {}
template <typename T> void assert_is_lvalue(const T&&) = delete;

int main() {
    const int n = 0;
    [=] { assert_is_lvalue(n); };
}

Clang compiles the code successfully, while GCC does not (error: use of deleted function). Which one is correct? Or is this something that is unspecified or implementation-defined?

Binding a reference to an object is supposed to odr-use it, and this is confirmed by removing the lambda's capture-default and observing that both compilers then complain that n can not be implicitly captured without a capture-default.

Marking the lambda as mutable makes no appreciable difference to the compilers' output.

like image 264
Oktalist Avatar asked Apr 29 '17 17:04

Oktalist


People also ask

Are lambda captures Const?

By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them.

What is capture in lambda function?

A lambda expression can refer to identifiers declared outside the lambda expression. If the identifier is a local variable or a reference with automatic storage duration, it is an up-level reference and must be "captured" by the lambda expression.

What is lambda capture list?

The capture list defines the outside variables that are accessible from within the lambda function body. The only capture defaults are. & (implicitly capture the used automatic variables by reference) and. = (implicitly capture the used automatic variables by copy).

Can lambda capture the local variable in Java?

Lambda expression in java Using a local variable is as stated. However, when a lambda expression uses a local variable from its enclosing scope, a special situation is created that is referred to as a variable capture. In this case, a lambda expression may only use local variables that are effectively final.


1 Answers

It turns out gcc behavior has changed from gcc-7.5 upward! I used the following code to see how n is captured within lambda and which template is matched.

#include <iostream>
#include <string>
#include <typeinfo>
#include <type_traits>
#include <memory>
#include <string>
#include <cstdlib>

template <class T>
constexpr std::string_view type_name()
{
    using namespace std;

    #ifdef __clang__
        string_view p = __PRETTY_FUNCTION__;
        return string_view(p.data() + 34, p.size() - 34 - 1);
    #elif defined(__GNUC__)
        string_view p = __PRETTY_FUNCTION__;

        #if __cplusplus < 201402
            return string_view(p.data() + 36, p.size() - 36 - 1);
        #else
            return string_view(p.data() + 49, p.find(';', 49) - 49);
        #endif
    #elif defined(_MSC_VER)
        string_view p = __FUNCSIG__;
        return string_view(p.data() + 84, p.size() - 84 - 7);
    #endif
}

template <typename T> 
void assert_is_lvalue(const T& param) 
{
    std::cout << "  T is " << type_name<T>() 
              << "  param is " << type_name<decltype(param)>() << '\n';
}

//template <typename T> void assert_is_lvalue(const T&&) = delete;
template <typename T> 
void assert_is_lvalue(const T&& param)
{
    std::cout << "  T is " << type_name<T>() 
              << "  param is " << type_name<decltype(param)>() << '\n';
}

int main() 
{
    const int n = 0;
    [=] { 
        std::cout << "  n is " << type_name<decltype(n)>() << '\n';
        assert_is_lvalue(n); 
    }();

    return 0;
}

and here are the results:

gcc-7.5

n is const int
T is int  param is const int&&

gcc-8.1

n is const int
T is int  param is const int&

you can play with the code here.

like image 75
Ali Avatar answered Nov 15 '22 22:11

Ali