在C++20中使用`std::bit_Cast`创建闭包(Lambda)对象是否有效? [英] Is it valid to create closure (lambda) objects using `std::bit_cast` in C++20?

查看:17
本文介绍了在C++20中使用`std::bit_Cast`创建闭包(Lambda)对象是否有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一位同事向我展示了一个C++20程序,其中的闭包对象是使用std::bit_cast从它捕获的值虚拟创建的:

#include <bit>
#include <iostream>

class A {
    int v;
public:
    A(int u) : v(u) {}
    auto getter() const { 
        if ( v > 0 ) throw 0;
        return [this](){ return v; }; 
    }
};

int main() {
    A x(42);
    auto xgetter = std::bit_cast<decltype(x.getter())>(&x);
    std::cout << xgetter();
}
由于出现异常,

HEREmain函数无法调用x.getter()。相反,它调用std::bit_cast,将闭包类型decltype(x.getter())作为模板参数,并将为新闭包对象xgetter捕获的指针&x作为普通参数。然后调用xgetter获取对象x的值,否则在main中无法访问。

程序被所有编译器接受,没有任何警告并打印42,demo:https://gcc.godbolt.org/z/a479689Wa

但是程序是否按照标准格式良好,这种lambda对象的"构造"是否有效?

推荐答案

但该程序是否符合标准...

该程序为实施者提供了undefined behaviour conditional on回旋余地。特别是根据lambda的闭合类型是否

[this](){ return v; }; 

很容易复制;根据[expr.prim.lambda.closure]/2

闭包类型在最小的块范围、类范围 或包含相应lambda表达式的命名空间范围。[.] 闭包类型不是聚合类型。和 实现定义的闭包类型可能与定义的不同 如果这不会改变可观察到的行为的话 除更改外:

  • (2.1)闭包类型的大小和/或对齐
  • (2.2)闭包类型是否可简单复制([class.prop])或
  • (2.3)闭包类型是否为标准布局类([class.prop])。[...]

这意味着[bit.cast]/1的约束是否满足:

template<class To, class From>
constexpr To bit_cast(const From& from) noexcept;

约束:

  • (1.1)sizeof(To) == sizeof(From)true
  • (1.2)is_­trivially_­copyable_­v<To>true;和
  • (1.3)is_­trivially_­copyable_­v<From>true

是实现定义的。

.这种lambda对象的"构造"是否有效?

as[expr.prim.lambda.闭包]/2.1还声明闭包类型的大小和对齐是由实现定义的,使用std::bit_cast创建闭包类型的实例可能会导致程序行为未定义,根据[bit.cast]/2

返回:To类型的对象。隐式创建嵌套在结果中的对象([Intro.Object])。结果的值表示的每一位等于From的对象表示中的对应位。未指定结果的填充位。对于结果和在其中创建的每个对象,如果没有与生成的值表示相对应的对象类型的值,则行为未定义。如果有多个这样的值,则未指定生成的值。

然而,对于任何类型的实际使用,我认为,如果一个构造有未定义的行为,条件是实现的回旋余地细节(除非这些可以用特征来查询),那么该构造应该合理地被认为具有未定义的行为,可能除了编译器的内部C++(例如Clang前端)实现,在那里这些实现细节是已知的。

这篇关于在C++20中使用`std::bit_Cast`创建闭包(Lambda)对象是否有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆