我使用“重载”模式来创建 std::variant 的访问者,将方法定义为带有通用 lambda 的 lambda,以提供空的默认方法。(稍后提供完整示例代码)
// imagine declaration of the overload template + the deduction helper here ...
using Foodstuff = std::variant<Fruit, Vegetable, Meat, Dairy, Fish>;
int things_eaten{0};
auto picky_eater = overload{
// Eats fruit
[&things_eaten](const Fruit&) { things_eaten++; },
// Eats dairy
[&things_eaten](const Dairy&) {things_eaten++; },
// Doesn't eat anything else - I need an empty handler for the other foodstuffs
[](auto) {}
};
Run Code Online (Sandbox Code Playgroud)
然后我用它作为std::visit食物的载体。在 MSVC 2022 (v17.7.6) 中针对 C++17 语言标准进行编译,我没有收到编译器警告(在 /W3),并且程序按照我在“发布”目标中的预期运行,但我更改了它当它退出函数时进行调试我得到异常
运行时检查失败#2 - 变量“picky_eater”周围的堆栈已损坏。
请注意,其他 lambda 具有捕获,而最终的泛型 lambda 没有,如果我将最后一个重载更改为[&things_eaten](auto) {},该异常就会消失。
此外,如果我将语言标准更改为 C++20,原始版本不会生成该异常。
该异常是否标识了原始代码中的真正问题,并且 C++20 是否引入了解决该问题的某些内容(也许模板推导发生了变化?)?这是调试构建中 MSVC C++17 运行时检查中的一个奇怪的错误(我没有其他编译器或分析工具可以比较)。
#include <variant>
#include <vector>
#include <string>
#include <iostream>
// Overload pattern
template <typename... Ts>
struct overload : Ts...
{
using Ts::operator()...;
};
// Template deduction helper; needed in C++17
template <typename... Ts>
overload(Ts...)->overload<Ts...>;
///////////////////////////////////////////////////////////
struct Fruit {
std::string name;
};
struct Vegetable {
std::string name;
};
struct Meat {
std::string name;
};
struct Dairy {
std::string name;
};
struct Fish {
std::string name;
};
using Foodstuff = std::variant<Fruit, Vegetable, Meat, Dairy, Fish>;
using Meal = std::vector<Foodstuff>;
int main() {
auto meal = Meal{ Fruit{"Apple"}, Vegetable{"Tomato"}, Meat{"Beef"}, Vegetable{"Potato"}, Dairy{"Yoghurt"} };
int things_eaten{ 0 };
auto picky_eater = overload{
// Eats fruit
[&things_eaten](const Fruit&) { things_eaten++; },
// Eats dairy
[&things_eaten](const Dairy&) { things_eaten++; },
// Doesn't eat anything else - I need an empty handler for the other foodstuffs
// If I write the generic lambda this way, MSVC in C++17 langauge standard will
// give an exception in Debug builds:
// "Run-Time Check Failure #2 - Stack around the variable 'picky_eater' was corrupted."
[](auto) {}
// But if I just add the same capture, even though it's not used, that error goes away?
// [&things_eaten](auto) {}
};
for (const auto& ingredient : meal) {
std::visit(picky_eater, ingredient);
}
std::cout << "I ate " << things_eaten << " things" << std::endl;
return 0;
// As the program exits, we get the exception
}
Run Code Online (Sandbox Code Playgroud)
您的代码看起来正确,可以进一步简化为
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded( Ts... )->overloaded<Ts...>;
int main() {
int i{ 0 };
auto lambda = overloaded{
[&i](int) {},
[](auto) {}
};
}
Run Code Online (Sandbox Code Playgroud)
同时保留 Visual Studio 中的堆栈损坏错误。
我向 MS 团队报告了它:https://developercommunity.visualstudio.com/t/Run-Time-Check-Failure-2---Stack-around/10510860
根据他们的回复,这是一个真正的编译器错误,该错误于 2019 年首次报告:https://developercommunity.visualstudio.com/t/Capturing-lambdas-in-function-object-res/475396
| 归档时间: |
|
| 查看次数: |
141 次 |
| 最近记录: |