gpt4 book ai didi

c++ - 在 Lambda 捕获中构建 intializer_list

转载 作者:搜寻专家 更新时间:2023-10-31 00:57:21 25 4
gpt4 key购买 nike

所以我在编造一个答案 here我需要使用 C++14's identifier initializer within a lambda capture :

const auto cmp = [ordering = { "dog", "cat", "mouse", "elephant" }](const string& lhs, const string& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); };

只要 ordering 就可以正常工作是一个 intializer_list<const char*> .但出于某种原因,如果我将它设为 intializer_list<string>,一切都会崩溃。 :

const auto cmp = [ordering = { "dog"s, "cat"s, "mouse"s, "elephant"s }](const string& lhs, const string& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); };

Live Example

我会说这是一个编译器错误,但我在 Visual Studio 中看到了一个更奇怪的问题,在使用 intializer_list<string> 时,一切都比较相等, 但一切都再次正常工作 intializer_list<const char*> ,可以将测试代码复制到http://webcompiler.cloudapp.net亲眼看看。

这实际上是 gcc Visual Studio 中的错误还是我做错了什么?

编辑:

将使用 cmp 的这些定义之一的给定代码:

map<string, int, function<bool(const string&, const string&)>> myMap(cmp);

myMap["cat"s] = 1;
myMap["dog"s] = 2;
myMap["elephant"s] = 3;
myMap["mouse"s] = 4;
myMap["rhino"s] = 5;

for (auto& i : myMap) {
cout << i.first << ' ' << i.second << endl;
}

在 Visual Studio 和 gcc 上使用 intializer_list<const char*>版本正确生成:

dog 2
cat 1
mouse 4
elephant 3
rhino 5

使用 intializer_list<string>http://ideone.com错误地生成:

cat 1
dog 2
mouse 4
elephant 5

并使用 intializer_list<string>在 Visual Studio 上错误地生成:

cat 5

最佳答案

恐怕这个错误在你的代码中。

问题是您在初始化 cmp 时正在复制/移动 lambda。对象,这意味着您失去了支持捕获的数组的生命周期扩展 initalizer_list .如果您通过引用绑定(bind)来延长 lambda 的生命周期,那么您的代码将至少适用于 ideone 和 coliru 上的 gcc 版本:

const auto& cmp = [ordering = { "dog"s, "cat"s, "mouse"s, "elephant"s }](const string& lhs, const string& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); };
^-- extend lifetime of lambda and thereby captured initializer_list

请注意,只有当原始生命周期延长的 lambda 至少与使用它的所有东西一样长时,这才有效。例如,您将无法返回 myMap来自封闭函数。

根据 lifetime of a std::initializer_list return value initializer_list 代理的临时数组生命周期延长至 initializer_list对象,与将引用绑定(bind)到临时对象相同。如果我们假设 CWG 1695适用于 initializer_list这与它应用于引用相同([dcl.init.list] 中的语言是 initializer_list 生命周期延长的行为“完全像将引用绑定(bind)到临时") 然后是 initializer_list init-capture 仅在封闭的 lambda 有效时才有效,并且仅当封闭的 lambda 本身通过引用绑定(bind)延长生命周期时才会在封闭范围内持续存在。

请注意,您的代码仍然无法在 clang 中运行,因为 clang does not implement CWG 1695 ,并且在 MSVC 中也不存在,出于同样的原因,我假设(我尝试了 CWG 1695 中的示例并得到了相同的结果;我还没有找到 MSVC 的错误报告)。

您的代码 initializer_list<char const*>之所以有效,是因为 initializer_list 的支持数组原始(平凡)类型的 s 可以被视为常量;您仍在访问悬空引用,但它恰好具有所需的值。我猜想 coliru 上的 gcc 版本选择将支持数组放置在已破坏的位置 string仍然可以使用销毁前的值访问 s;不管怎样,您仍在访问已破坏的对象。

关于c++ - 在 Lambda 捕获中构建 intializer_list<string>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37621932/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com