【问题标题】:Calling std::any_of with conditional operator on lambda gives unexpected results在 lambda 上使用条件运算符调用 std::any_of 会产生意想不到的结果
【发布时间】:2013-06-09 18:38:40
【问题描述】:

这是我最近在VS2012中写的一些代码:

    ///<summary>Lambda: Returns true if the field is significant within a baseline context</summary>
    const auto IsSignificantBaselineField = [](const field_info & field)->bool
    {
        //Some lines removed here!
        return something;
    };

    ///<summary>Lambda: Returns true if the field is significant within a project context</summary>
    const auto IsSignificantProjectField = [&IsSignificantBaselineField](const field_info & field)->bool
    {
        if (!IsSignificantBaselineField (field))
            return false;

        //Some lines removed here!
        return something_else;
    };

    return std::any_of (modified_fields.begin (), modified_fields.end (), (proj_id == 0) ? IsSignificantProjectField : IsSignificantBaselineField);

奇怪的是,当 'proj_id = 90000' 时,IsSignificantProjectField 被 std::any_of 调用,而我的意图是在这种情况下调用 IsSignificantBaselineField。

谁能解释我的逻辑错误?

【问题讨论】:

  • 这个编译?它不应该。两个 lambdas 的类型之间没有共同的类型。
  • 是的,它在 VS2012 中编译干净。我没有想到没有常见的类型,但这对我来说听起来很合理。
  • 嗯,这不仅仅是报告它。照原样,没有人可以帮助您解决问题,因为我们无法重现它(它不会为我们编译!)。弄清楚是什么让你的代码编译将帮助我们解释如何解决你的问题,或者至少想出一个解决方法。
  • @R.MartinhoFernandes:我尝试了auto x = (i &lt; 100) ? a : b;,其中const auto a = []{return false;};const auto b = []{return true;}; 在g++ 4.8 中编译。这是不正确的标准吗?即如果 lambda 的原型相同,可以这样做吗? VC++ 哭了 没有可以执行此转换的用户定义的转换运算符
  • @legends2k 这是正确的,因为 captureless lambda 可以转换为函数指针。 AFAIK VS 还没有实现。

标签: c++ c++11 lambda conditional-operator c++-standard-library


【解决方案1】:

所以这是我的猜测,为什么代码会编译并显示您观察到的行为。

编译器都将 lambda 转换为结构。

一个没有捕获,因此没有成员和无参数构造函数。

struct IsSignificantBaselineField_Lambda {
  bool operator ()(const field_info & field) { ... }
};

另一个有一个捕获,转换为一个成员和一个单参数构造函数。

struct IsSignificantProjectField_Lambda {
  IsSignificantProjectField_Lambda(IsSignificantBaselineField_Lambda& capture1)
    : m_capture1(capture1) {}
  bool operator ()(const field_info & field) {
    if (!m_capture1(field)) return false;
    ...
  }
private:
  IsSignificantBaselineField_Lambda& m_capture1;
};

我敢打赌,编译器的转换不会使构造函数explicit,从而使其成为转换构造函数,这意味着 IsSignificantBaselineField 可以转换为 IsSignificantProjectField,因此 IsSignificantProjectField 是两者的通用类型。所以调用相当于:

return std::any_of (modified_fields.begin (), modified_fields.end (),
    (proj_id == 0) ? IsSignificantProjectField :
                     IsSignificantProjectField_Lambda(IsSignificantBaselineField));

最终效果是两个分支都做同样的事情。

这当然是一个编译器错误。

【讨论】:

  • 精彩 - 推演得很好!这很可能是正确的解释。
猜你喜欢
  • 2015-07-22
  • 2015-09-24
  • 2017-03-19
  • 2021-10-04
  • 1970-01-01
  • 2017-07-05
  • 2017-02-10
  • 2015-02-12
  • 2021-06-27
相关资源
最近更新 更多