13

I have a small lambda function which shall find and return a QTreeWidgetItem. But if it does not find the given item, then it shall return a nullptr. But if I try to compile it then it gives me an error.

The function:

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.
};

The error:

Error 1 error C3487: 'nullptr': all return expressions in a lambda must have the same type: previously it was 'QTreeWidgetItem *' cpp 251

I changed the mentioned line with this and now it compiles:

return (QTreeWidgetItem*)( nullptr );

but I would like to avoid this syntax. How can I solve this ?

I use Visual Studio 2012.

4
  • This looks like a bug in VS2012? Commented Jun 11, 2015 at 14:46
  • @Yakk: Why? The error message is quite clear, isn't it? Commented Jun 11, 2015 at 17:32
  • @MSalters Hmm. Strange, I actually thought that so long as the later return types are compatible (implicitly convertible) the first return type, everything was a-ok. Commented Jun 11, 2015 at 18:02
  • IIRC the lambda proposal for C++11 was intentionally conservative. Some fairly reasonable extensions were left out just to be safe. Commented Jun 11, 2015 at 20:27

3 Answers 3

19

You can add an explicit return type annotation:

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

That way nullptr will be converted to your pointer type properly. You're getting that error because the lambda assumes no conversions should be made, and treats nullptr_t as a legitimate alternative return type.


As a side note, consider using (std::)optional instead. The nullability of pointers can be used to represent a missing return, but it doesn't mean it necessarily should be.

Sign up to request clarification or add additional context in comments.

3 Comments

I disagree with the last point concerning optional: most stuff in Qt is passed by pointers, and I believe that the result of this lambda is passed somewhere to Qt. Also, it is just better to follow their style, even if it may be evil in modern C++.
@lisyarus Hence consider. It doesn't necessarily have to make sense in this particular example, but may be an option for another reader.
Consider removing the last comment about using std::optional instead of returning a nullptr. I don't think it makes your answer any better. The top part is just perfect.
4

If you just want to avoid the syntax, rather than the casting, you could it like this:

static_cast<QTreeWidgetItem*>(nullptr);

I made a small example, on how Bartek's and mine's answer really work:

#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;
}

7 Comments

Why shouldn't your example compile fine? The parameter struct could be ommited entirely, leaving a lambda which return type is just nullptr_t.
You answer is far better @BartekBanachewicz . Deleting mine and giving a +1 to you.
Your static_cast remark was perfectly fine though.
I'd leave just the static_cast bit (because the code sample is clearly not relevant here).
static_cast has more "force" than an implicit conversion, so I'd generally prefer one of the other solutions for that reason.
|
0

I had this very same issue with some Smart Pointers, so I found I could do this to avoid the issue:

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

Similarly, for shared pointer, just repleace MyPointer* by std::shared_ptr<MyPointer>.

So your code would looks like:

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;
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.