c++ - 无状态 lambda 作为静态局部变量

标签 c++ templates lambda c++17

我正在尝试围绕无状态 lambda 编写一个模板化包装类。像这样的事情:

template <class TFuncOp>
class Adapter
{
public:
    void Op()
    {
        TFuncOp func; // not possible before C++20
        func();
    }
};

由于在 C++20 提供默认可构造 lambda 之前这是不可能的,因此我使用此技术来使我的类正常工作:Calling a stateless lambda without an instance (only type)

所以最终的解决方案如下所示:

template <class TFuncOp>
class Adapter
{
public:
    static TFuncOp GetOpImpl( TFuncOp *pFunc = 0 )
    {
        static TFuncOp func = *pFunc;
        return func;
    }

    void Op()
    {
        GetOpImpl()();
    }
};

template <class TFuncOp>
Adapter<TFuncOp> MakeAdapter(TFuncOp func )
{
    // Removing the line below has no effect.
    //Adapter<TFuncOp>::GetOpImpl( &func );
    return Adapter<TFuncOp>();
}

int main()
{
    auto adapter = MakeAdapter( [] { printf("Hello World !\n"); } );
    adapter.Op();
    return 0;
}

此代码适用于所有主要编译器(clang、gcc、msvc)。但有一个令人惊讶的发现。 GetOpImpl() 中 lambda 的静态本地实例的初始化(或缺少初始化)没有效果。无论哪种方式都可以正常工作。

谁能解释一下这是如何工作的?如果我使用 lambda 的静态本地实例而不初始化它,我是否会调用 UB?

最佳答案

无论如何,访问 nullptr 从来都不是一个好主意,因为它是 UB。

但是我们可以看到典型的实现生成的代码可以简单地工作。我尝试解释一下原因:

首先,它与 lambda 无关。这只是在没有数据的类上不需要使用复制构造函数。由于没有数据,生成的代码将不会访问传递的对象。在您的情况下,您“复制”指针 TFuncOp *pFunc = 0 指向的对象,该对象是一个 nullptr,如果必须访问该对象,它将崩溃。由于没有数据可供访问,典型的实现根本不会生成任何访问 nullptr 的代码。但它仍然是UB。

同样的方法适用于所有其他类型,并且 lambda 没有什么特别之处!

struct Empty
{
    void Do() { std::cout << "This works the same way" << std::endl; }
    // int i; // << if you add some data, you get a seg fault
};

int main()
{
    Empty* ptr = nullptr;
    Empty empty = *ptr; // get seg fault here, because default copy constructor access the nullptr, but typically only if copy ctor needs to access!

    empty.Do();
}

没有捕获数据的 lambda 是一个带有 operator()() 的空结构。

这一切都是一个答案为什么它似乎有效。

关于c++ - 无状态 lambda 作为静态局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64178997/

相关文章:

c++ - XPCOM C++ : Does it support RegExps?

c# - 使用 Rhino.Mocks 检查传递给委托(delegate)的预期值

c++ - 有没有办法将 "inherit"设为 int 等基类型?

c++ - 抑制 C++ 中未使用的变量警告 => 编译器错误或代码错误?

c++ - 奇怪的重复模板模式——继承和 friend

c++ - 使用模板的嵌套类中的未知类型名称 'class'

java - 动态添加到 lambda 表达式

Java Lambda 与方法引用 - 不接收调用者的本地变量

c++ - 将 gSOAP 与 2 个不同的 wsdl 文件一起使用时出现链接器错误

C++:抛出异常调用复制构造函数?