Search code examples
c++polymorphismtypeidtypeinfo

c++ Is it possible to pass an object type into a function to be compared against


I have a situation where I need to find out if a derived object is stored in a vector within another object, and want to functionize this. I can't figure out a way to do exactly what I want, or determine whether it is possible. I have a solution that works which I'm including, but it would be cleaner if there is a direct method to achieve the goal.

This is essentially what I want to do:

class IFruit
{
public:
    virtual ~IFruit(){};
};
class Apple : public IFruit {};
class Banana : public IFruit {};
class Orange : public IFruit {};

class FruitBowl
{
public:
    bool HasFruit( datatype?? FruitType )
    {
        for ( auto iter : m_Fruit )
        {
            if ( typeof( iter ) == typeof( FruitType ) )
            {
                return ( true );
            }
        }
        return ( false );
    }

    vector< IFruit* > m_Fruit;
};

int main()
{
    FruitBowl Snacks;
    Snacks.m_Fruit.push_back( new Banana );
    Snacks.m_Fruit.push_back( new Apple );
    Snacks.m_Fruit.push_back( new Orange );

    if ( Snacks.HasFruit( Orange ) )
    {
        cout << "There is an orange available";
    }

    return ( 0 );
}

This is a workaround that achieves the goal, but it has the extra step of providing the callback which I'd love to eradicate:

#include <vector>
#include <iostream>
#include <functional>
using namespace std;

class IFruit
{
public:
    virtual ~IFruit(){};
};
class Apple : public IFruit {};
class Banana : public IFruit {};
class Orange : public IFruit {};

class FruitBowl
{
public:
    bool HasFruit( function< bool( IFruit* ) > fnCompareFruitType )
    {
        for ( auto iter : m_Fruit )
        {
            if ( fnCompareFruitType( iter ) )
            {
                return ( true );
            }
        }
        return ( false );
    }

    vector< IFruit* > m_Fruit;
};

int main()
{
    FruitBowl Snacks;
    Snacks.m_Fruit.push_back( new Banana );
    Snacks.m_Fruit.push_back( new Apple );
    Snacks.m_Fruit.push_back( new Orange );

    if ( Snacks.HasFruit( []( IFruit* TestFruit ){ return ( dynamic_cast< Orange* >( TestFruit ) != nullptr ); } ) )
    {
        cout << "There is an orange available";
    }

    return ( 0 );
}

Solution

  • You can't pass a type as a runtime function parameter, but you can use one as a compile time template parameter of a function template:

    #include <vector>
    #include <iostream>
    #include <algorithm>
    
    class IFruit
    {
    public:
        virtual ~IFruit(){};
    };
    class Apple : public IFruit {};
    class Banana : public IFruit {};
    class Orange : public IFruit {};
    
    class FruitBowl
    {
    public:
        template <typename T>
        bool HasFruit()
        {
            return std::any_of(m_Fruit.begin(), m_Fruit.end(),
                              [](IFruit* fruit) {
                                  return dynamic_cast<T*>(fruit) != nullptr;
                              });
        }
    
        std::vector< IFruit* > m_Fruit;
    };
    
    
    int main()
    {
        FruitBowl Snacks;
        Snacks.m_Fruit.push_back( new Banana );
        Snacks.m_Fruit.push_back( new Apple );
        Snacks.m_Fruit.push_back( new Orange );
    
        if ( Snacks.HasFruit<Orange>() )
        {
            std::cout << "There is an orange available";
        }
    }