Can I make a table of String + lambdas that have the same signature?中的先前调查显示我在VS2010中实际上可以有一个字符串+ lambdas表。
当lambdas是无效返回类型时,事情看起来很好。但是试图将它们更改为bool返回类型,编译器似乎弄错了,或者存在某种内存损坏错误......在C ++版本中这是不正确的......
以下说明了该方案:
// fun: use a table of lambdas to define what to do in order to update each field
typedef std::function<bool (CDynamicMenuItem *, ITEM *)> LambdaType;
struct UpdateField {
const TCHAR * label;
LambdaType lambda; // this version allows us to use captures in our lambdas, whereas the following doesn't
//void (*lambda)(CDynamicMenuItem *, ITEM *); // this would work in VS11, but the conversion of lambda to function pointer was defined after 2010's release!
};
UpdateField MenuFields[] = {
{ "Identity", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { return pMenuItem->SetText(FString("%s/%.1f", pNearestItem->thissec->name, pNearestItem->number/10.0)), true; } },
{ "X1", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetX1(pNearestItem); return (v != v) ? false : pMenuItem->SetValue(v), true; } },
{ "Y1", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetY1(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
{ "X2", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetX2(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
{ "Y2", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetY2(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
{ "Xd", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetXd(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
{ "Yd", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetYd(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
{ "Angle", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetAngle(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
{ "Length", [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { double v = GetLength(pNearestItem); if (v != v) return false; pMenuItem->SetValue(v); return true; } },
};
for (UpdateField * it = &MenuFields[0], * end = (MenuFields + countof(MenuFields)); it != end; ++it)
{
CDynamicMenuItem * pMenuItem = pMenu->FindItem(it->label);
if (pMenuItem)
{
if (!m_pNearestItem || !it->lambda(pMenuItem, m_pNearestItem))
pMenuItem->SetText("");
}
}
当lambda的返回类型为void(即 - &gt; bool被省略,并且各种lambda体被修改为不返回任何内容等)时,上述工作非常漂亮。
然而,让我们返回一个bool来指示lambda是否能够处理该字段的数据是否有用,如果没有,则让调用者处理清除该字段。
确定,代码编译&amp;运行...直到它达到此代码&amp;崩溃。在调试器中查看“MenuFields []”会显示大多数MenuField [x] .label地址的垃圾(有时其中一个是正确的,但我还没弄清楚模式是什么)。
我想也许编译器在静态初始化列表中嵌入了lambda的语法,但是我不知道我能做些什么呢?
我尝试了这种变化:
{ "Identity", LambdaType( [] (CDynamicMenuItem * pMenuItem, ITEM * pNearestItem) ->bool { return pMenuItem->SetText(FString("%s/%.1f", pNearestItem->thissec->name, pNearestItem->number/10.0)), true; } ) },
编译器同样喜欢这样,但它会导致相同的损坏的表数据。
类似地,编译器可以在整个lambda周围放置括号,并且在运行时同样会损坏。
所以,有些问题:
答案 0 :(得分:3)
这确实是Visual C ++编译器中的一个错误。请参阅错误报告"miscompilation of aggregate initializer with lambdas inside"。
作为解决方法,请考虑不在此处使用聚合初始化。相反,您可以使用std::vector
:
UpdateField MakeUpdateField(char const* label, LambdaType const lambda)
{
UpdateField f = { label, lambda };
return f;
}
std::vector<UpdateField> fields = ([]() -> std::vector<UpdateField>
{
std::vector<UpdateField> data;
data.push_back(MakeUpdateField("Identity", [] { /* contents omitted */ }));
data.push_back(MakeUpdateField("X1", [] { /* contents omitted */ }));
data.push_back(MakeUpdateField("Y1", [] { /* contents omitted */ }));
return data;
})();
(如果您的数据是名称到lambda的映射,您可能还会考虑使用std::map
,这可能会提供更好的性能特征,或者可能更容易使用。)