I am trying to use lambdas to find a way to find how many specific derived classes are in a vector of Base class type.
std::vector<std::unique_ptr<Account>> openedAccounts;
int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(),
[](std::unique_ptr<Account> ptr) { return dynamic_cast<Current&>(*ptr) != nullptr; }); // I will call this for savings as well
The account is a base abstract class and the current is a derived class.
I am getting the error no operator != matches these operands".
HOwever, I thought dynamic cast can return a null ptr.
CodePudding user response:
A dynamic cast returns exactly what you asked for.
You asked for Current&
or a Current reference.
You probably want to ask this
return dynamic_cast<Current*>(ptr.get()) != nullptr;
CodePudding user response:
I thought dynamic cast can return a null ptr.
Only when you dynamic cast into a pointer type.
References don't have a representation for null. When you dynamic cast into a reference type, then an exception will be thrown in cases where a pointer cast would have returned null.
what is the way to go about this then?
dynamic_cast<Current*>(ptr.get())
would work. However, designs that require dynamic_cast
are often probably bad. dynamic_cast
exists for mostly working around badly designed APIs.
I recommend considering alternative designs.
CodePudding user response:
std::vector<std::unique_ptr<Account>> openedAccounts; int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(), [](std::unique_ptr<Account> ptr) { return dynamic_cast<Current&>(*ptr) != nullptr; }); // I will call this for savings as well
I see in this code 3 problems:
dynamic_cast<Current&> ... != nullptr
-dynamic_cast
throws an exception for references and never returnsnull_ptr
.- Lambda is incorrect, since argument
std::unique_ptr<Account>
is an attempt to create a copy of something what should be unique. - if you have container of pointers to some abstraction and you have to do
dynamic_cast
then this is clear indication that abstraction used is invalid.
So this should look looks more like this:
class Account {
public:
virtual bool isCurrent() { return false; }
....
};
std::vector<std::unique_ptr<Account>> openedAccounts;
int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(),
[](const std::unique_ptr<Account>& ptr) { return ptr->isCurrent(); });
I undesutnd that last point is hard to process so here is the hacky fix:
int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(),
[](const std::unique_ptr<Account>& ptr) { return dynamic_cast<Current *>(ptr.get()) != nullptr; });