sizeof可以在lambda中应用于未捕获的变量,还是编译器错误?

Cla*_*tus 7 c++ c++11

这是此处讨论的后续内容.

以下代码在gcc和clang(实时演示)下编译.//1由于lambda没有捕获任何东西,因此对于该情况而言这是令人惊讶的.对于MCR2lambda返回指针本身的情况,我们得到预期的编译时错误(行// Will not compile).运算符的应用sizeof与返回指针有何不同?

#include <iostream>

#define MCR1(s) \
  ([]() { return sizeof(s); })()

#define MCR2(s) \
  ([]() { return s; })()

int main() {
  auto *s= "hello world";

  auto x1 = MCR1( s ); //1
  auto y1 = MCR1( "hello world" );
//  auto x2= MCR2( s ); // Will not compile
  auto y2= MCR2( "hello world" );

  std::cout << x1  << "  " << y1  << '\n';
  std::cout // << x2 << "  " 
            << y2 << '\n';
}
Run Code Online (Sandbox Code Playgroud)

编辑:继续讨论这里是另一个例子.令人惊讶的是,标记的行//2现在编译在gcc7(开发版)(现场演示)下.这里的区别在于表达式已被标记constexpr,现在.

#include <iostream>

#define MCR1(s) \
  ([]() { return sizeof(s); })()

#define MCR2(s) \
  ([]() { return s; })()

int main() {
  auto constexpr *s= "hello world";

  auto constexpr x1= MCR1( s );
  auto constexpr y1= MCR1( "hello world" );
  auto constexpr x2= MCR2( s );             //2
  auto constexpr y2= MCR2( "hello world" );

  std::cout << x1 << "  " << y1 << '\n';
  std::cout << x2 << "  " << y2 << '\n';
}
Run Code Online (Sandbox Code Playgroud)

krz*_*zaq 6

不同之处在于(缺乏)上下文评估.sizeof没有评估.

根据N3337(≈C++ 11)

§5.12[expr.prim.lambda]/11

如果lambda表达式具有关联的capture-default及其 复合语句 odr-uses this或具有自动存储持续时间的变量,并且未明确捕获使用odr的实体,则称该odr-used实体被隐式捕获 ;

§5.1.2[expr.prim.lambda]/12

如果lambda表达式使用odr this或具有自动存储持续时间的变量,则该实体应由其捕获lambda-expression.如果lambda表达式捕获实体并且未在紧邻的lambda表达式或函数中定义或捕获该实体,则该程序格式错误.

ODR使用意味着在潜在的评估环境中使用:

§3.2[basic.def.odr]/2

一个表达式是可能评价,除非它是一个未计算的操作数或它们的子表达式.名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式中的要求的对象,并且立即应用左值到右值的转换

由于sizeof不是,并且s正在达到 lambda表达式的范围,所以没关系.s然而,回归意味着评估它,这就是为什么它形成不良.

  • @ClaasBontus到目前为止,我们有一个轶事,它"令人惊讶".如果lambda语法不允许,我会更惊讶.首先,它会让它充分破碎,对于许多常见用途来说是无用的. (2认同)

Okt*_*ist 5

Lambda 可以“看到”周围范围内的许多事物,而无需捕获它们:

-- 全局变量:

int x = 42;
int main() { []{ std::cout << x; }(); }
Run Code Online (Sandbox Code Playgroud)

-- 静态局部变量:

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

- 功能:

int x() { return 42; }
int main() { []{ std::cout << x(); }(); }
Run Code Online (Sandbox Code Playgroud)

-- 类型:

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

-- 在未计算的上下文中使用的局部变量:

int main() {
    int x = 42;
    []{ std::cout << sizeof(x); }();
}
Run Code Online (Sandbox Code Playgroud)

这自然不符合语言规则。您可以在 C++98 中使用手写的可调用对象执行相同的操作:

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

这并不奇怪,因为sizeof没有评估它的表达式:

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;
}
Run Code Online (Sandbox Code Playgroud)