如何从Lambda函数中返回nullptr?

12

我有一个小的lambda函数,它将查找并返回一个QTreeWidgetItem。但是如果它没有找到所给定的项目,则应该返回nullptr。但是,如果我尝试编译它,那么就会出现错误。

该函数:

auto takeTopLevelItem = []( QTreeWidget* aTreeWidget, const QString& aText )
{
    const int count = aTreeWidget->topLevelItemCount();
    for ( int index = 0; index < count; ++index )
    {
        auto item = aTreeWidget->topLevelItem( index );
        if ( item->text( 0 ) == aText )
        {
            return aTreeWidget->takeTopLevelItem( index );
        }
    }
    return nullptr; // This causes a compilation error.
};

错误:

错误1:错误 C3487:'nullptr':lambda中的所有返回表达式必须具有相同的类型:之前它是'QTreeWidgetItem *' cpp 251

我用以下代码替换了上述行,现在它可以编译:

return (QTreeWidgetItem*)( nullptr );

但我希望避免使用这种语法。我该如何解决?

我使用 Visual Studio 2012


这看起来像是VS2012中的一个bug? - Yakk - Adam Nevraumont
@Yakk:为什么?错误信息很清楚,不是吗? - MSalters
@MSalters 嗯。奇怪的是,我认为只要后面的返回类型是兼容的(可以隐式转换)第一个返回类型,一切都没问题。 - Yakk - Adam Nevraumont
据我所知,C++11中的lambda提案意图保守。为了安全起见,一些相当合理的扩展被省略掉了。 - MSalters
3个回答

16

你可以添加显式的返回类型注释:

auto takeTopLevelItem = []( ... ) -> QTreeWidgetItem*
{
    // ...
}

这样做可以使 nullptr 被正确转换为指针类型。您之所以会出现这个错误,是因为lambda函数假定不应进行任何转换,并将 nullptr_t 视为合法的替代返回类型。


另外,请考虑使用(std ::)optional。指针的可空性可以用于表示缺少的返回值,但这并不意味着一定要这样做。


5
我不同意关于“可选”的最后一点:在 Qt 中,大多数内容都是通过指针传递的,我相信这个 lambda 表达式的结果会被传递到某个 Qt 中。而且,即使在现代 C++ 中可能有些不好,遵循他们的风格也是更好的选择。 - lisyarus
1
因此考虑一下。它不一定在这个特定的例子中有意义,但可能是另一个读者的选项。 - Bartek Banachewicz
1
考虑删除关于使用std::optional而不是返回nullptr的最后一条评论。我认为这并不能使你的答案更好。顶部部分已经很完美了。 - Ralph Tandetzky

4
如果你只是想避免语法而不是转换,那么你可以像这样做:
static_cast<QTreeWidgetItem*>(nullptr);

我做了一个小例子,演示了Bartek和我回答的真正作用:

#include <iostream>

class A {
  int a;
};

auto bla = [] (A* obj, bool flag) -> A* {
  if(flag)
    return obj;
  return nullptr;
//  return static_cast<A*>(nullptr);
};

int main() {
  A obj;
  A* ptr = &obj;
  bool flag = false;
  if( bla(ptr, flag) == nullptr)
    std::cout << "ok\n";
  return 0;
}

1
为什么你的示例不能编译通过呢?参数结构体可以完全省略,只需一个返回类型为 nullptr_t 的 lambda 表达式即可。 - Bartek Banachewicz
你的回答比@BartekBanachewicz好得多。我会删除我的回答并给你一个+1。 - gsamaras
你的static_cast备注是完全正确的。 - Bartek Banachewicz
嗯,你会建议什么?只使用 static_cast 编辑答案还是全部删除?@BartekBanachewicz - gsamaras
1
我会只留下 static_cast 部分(因为代码示例在这里显然不相关)。 - Bartek Banachewicz
好的@BartekBanachewicz。 仔细想想,我发布了另一个示例,这将允许未来的读者进行操作(并且还证明了我们的正确性)。 - gsamaras

0

我曾经在使用一些智能指针时遇到了同样的问题,所以我发现可以这样做来避免这个问题:

auto myFunc= [](MyClass* class)
{
    MyPointer* pointer = nullptr;
    
    if( class && class->isValid() )
    {
       pointer = class->getPointerInstance()
    }
    
    return pointer;
}

同样地,对于共享指针,只需将MyPointer*替换为std::shared_ptr<MyPointer>
因此,您的代码应该如下所示:
auto takeTopLevelItem = []( QTreeWidget* aTreeWidget, const QString& aText )
{
  QTreeWidgetItem* item = nullptr;
  const int count = aTreeWidget->topLevelItemCount();
  for ( int index = 0; index < count; ++index )
  {
      auto item = aTreeWidget->topLevelItem( index );
      if ( item->text( 0 ) == aText )
      {
          item = aTreeWidget->takeTopLevelItem( index );
          break;
      }
  }
  return item;
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接