Can sizeof be applied inside a lambda on a variable that is not captured or is this a compiler bug?

前端 未结 2 1023
粉色の甜心
粉色の甜心 2021-01-12 11:46

This is a follow up of the discussion found here.

The following code compiles both under gcc and clang (live demo). This is surprising for the case in line //1

相关标签:
2条回答
  • 2021-01-12 12:42

    Lambdas can "see" a lot of things in their surrounding scope without needing to capture them:

    -- Global variables:

    int x = 42;
    int main() { []{ std::cout << x; }(); }
    

    -- Static local variables:

    int main() {
        static int x = 42;
        constexpr int y = 1337;
        []{ std::cout << x << y; }();
    }
    

    -- Functions:

    int x() { return 42; }
    int main() { []{ std::cout << x(); }(); }
    

    -- Types:

    using x = std::integral_constant<int, 42>;
    int main() { []{ std::cout << x::value; }(); }
    

    -- Local variables used in unevaluated contexts:

    int main() {
        int x = 42;
        []{ std::cout << sizeof(x); }();
    }
    

    This just naturally falls out of the language rules. You can do the same thing in C++98 with a hand-written callable object:

    int main() {
        int x = 42;
        struct functor {
            int operator()() const { return sizeof(x); }
        };
        std::cout << functor{}();
    }
    

    It's unsurprising, as sizeof does not evaluate its expression:

    int main() {
        int x; // uninitialized
        using y = std::integral_constant<size_t, sizeof(x)>; // x used in a constant expression
    
        using z = std::integral_constant<size_t, 4>;
        static_assert(std::is_same<y, z>::value, "");
    
        std::cout << y::value;
    }
    
    0 讨论(0)
  • 2021-01-12 12:43

    The difference is the (lack of) evaluation of context. sizeof is unevaluated.

    As per N3337 (≈C++11)

    §5.1 2 [expr.prim.lambda] / 11

    If a lambda-expression has an associated capture-default and its compound-statement odr-uses this or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured;

    and

    §5.1.2 [expr.prim.lambda] / 12

    If a lambda-expression odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression. If a lambda-expression captures an entity and that entity is not defined or captured in the immediately enclosing lambda expression or function, the program is ill-formed.

    ODR use means use in potentially evaluated context:

    §3.2 [basic.def.odr] / 2

    An expression is potentially evaluated unless it is an unevaluated operand or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied

    Since sizeof isn't, and s is in reaching scope of the lambda expression, it is okay. Returning s means evaluating it, though, and that's why it's ill-formed.

    0 讨论(0)
提交回复
热议问题