如何在标准函数 lambda c++ 11 中正确捕获参数包

Posted

技术标签:

【中文标题】如何在标准函数 lambda c++ 11 中正确捕获参数包【英文标题】:How to correctly capture parameter pack in std function lambda c++ 11 【发布时间】:2021-11-09 10:12:36 【问题描述】:

我一直在尝试在 std 函数 lambda 中捕获一些参数包参数,以便将函数保存在内存中以供将来使用。

但是,在某些情况下,如果这些捕获参数中的任何值在捕获后被修改,那么这些参数的未来用途就不是预期的。

我想在我的 std 函数中存储参数包的不可变副本。

此代码将作为库实现,因此用户可以使用它来保存一些文本以供将来打印。这样我们就无法管理我们在参数包中收到的参数。这个例子必须对字符串有效,const char *, int, float, ...

这是一个示例代码:Code link

template <typename... Args>
void doPrint(std::ostream& out, const Args &... args)

    using expander = int[];
    (void)expander0, (void(out << args), 0)...;


template<typename... Args>
void printArgs(const Args & ... args)

    doPrint(std::cout, args...);


class PrintTest

private:

    std::vector<std::function<void()>> myFunctions;   

public:

    template<typename... Args>
    void saveText(const char * text, const Args & ... args)
    
        std::function<void()> f = [this, text, args...]()
        
            std::cout << text;
            printArgs(args ...);
            std::cout << std::endl;
        ;

        this->myFunctions.push_back(f);
    

    void printSavedTexts()
    
        for(auto fun : this->myFunctions)
            fun();

        this->myFunctions.clear();
    

;

int main()

    PrintTest test;

    
        int four = 4;
        test.saveText(" Hello world ", 1, 2, 3, std::to_string(four).c_str());

        std::string a ="Just";
        const char * b = " be ";
        test.saveText(" Bye, Bye! ", a.c_str(), b, std::string("yourself!").c_str());
        a = "?";

        for(int i = 0; i <= 5; ++i)
        
            std::string n = std::to_string(i);
            test.saveText("", n.c_str());
        
    

   test.printSavedTexts();

这个例子的输出是:

// Hello world 1234
// Bye, Bye! ? be yourself!
// 5
// 5
// 5
// 5
// 5
// 5

它应该是:

// Hello world 1234
// Bye, Bye! Just be yourself!
// 0
// 1
// 2
// 3
// 4
// 5

有没有更好的方法将接收到的文本和参数包保存在内存中以备将来使用?而不是使用存储在vector中的std函数。

【问题讨论】:

您可能想要传递字符串 test.saveText("", n); 本身。见godbolt.org/z/Yndsv9dT6 @Const 此代码将作为库实现,因此用户可以使用它来保存一些文本以供将来打印。这样我们就无法管理我们在参数包中收到的参数。这个例子必须对字符串有效,const char *, int, float, ... 【参考方案1】:

test.saveText("", n.c_str()); 中,您将从n 获得的const char* 指针传递给saveText,最后被lambda 捕获。当退出for 循环时,n 被破坏,捕获的指针悬空。对他们的尊重会导致 UB。

你可以像test.saveText("", n);一样直接使用std::string;即删除所有.c_str()s。

LIVE

【讨论】:

没错,谢谢。然而,这只是一个简单的例子。我正在尝试将此代码实现为一个必须支持所有可能的参数类型的库,而不仅仅是标准字符串。 @Samuel 那么你必须小心原始指针;确保它们在 lambdas 中使用时仍然有效。 有没有办法管理在参数包中接收到的原始指针?或者与使用 std 函数不同的方式将接收到的参数包保存在内存中以供将来使用? @Samuel 在参数包中专门处理原始指针并不容易;我仍然认为保持指针有效,或者从一开始就传递std::string 或智能指针是调用者的责任。

以上是关于如何在标准函数 lambda c++ 11 中正确捕获参数包的主要内容,如果未能解决你的问题,请参考以下文章

c++中lambda表达式用法

lambda 函数 C++ 11

看看 C++ 的 Lambda 表达式

如何在 C++ 中定义匿名函数?

C++培训 lambda

C ++中的Lambda函数,参数和逻辑[重复]