DeSubstantiisSeparatis
DeSubstantiisSeparatis

Reputation: 110

Doing dynamic_cast over parameter pack

Consider such code:

struct A
{
    A() = default;
    virtual ~A() = default;
};

struct B : public A
{
    B() = default;
    virtual ~B() = default;
};

struct C : public A
{
    C() = default;
    virtual ~C() = default;
};

struct D : public A
{
    D() = default;
    virtual ~D() = default;
};

struct E : public A
{
    E() = default;
    virtual ~E() = default;
};


template <typename CLASS1, typename CLASS2>
bool AreObjectsEqual(std::vector<A*>& vec)
{
    return std::all_of(vec.begin(), vec.end(),
    [](const auto v) { return (dynamic_cast<CLASS1*>(v) != nullptr || dynamic_cast<CLASS2*>(v) != nullptr); });
}

int main()
{
    std::vector<A*> vec = { new D{}, new C{} };
    std::cout << AreObjectsEqual<D, C>(vec) << std::endl;
    std::vector<A*> vec1 = { new D{}, new C{}, new E{} };
    std::cout << AreObjectsEqual<E, C>(vec) << std::endl;
    return 0;
}

Above code checks whether a vector of pointers contains objects that can be casted into some classes. But what I really would like to do is to check more that two templates. Something like:

template <typename... CLASSES>
bool AreObjectsEqual(std::vector<A*>& vec)
{
    return std::all_of(vec.begin(), vec.end(),
        [](const auto v)
        {
            bool false = true;
            for(auto CLASS : CLASSES)
                retValue ||= (dynamic_cast<CLASS*>(v) != nullptr);

            return retValue;
        });
}

std::cout << AreObjectsEqual<B, C, D, E>(vec) << std::endl;

Is it possible to achieve that? Every examples of code with parameter pack had also an argument with parameter pack, and I don't need that. I just need to know how to iterate over template... CLASSES

Upvotes: 0

Views: 196

Answers (1)

cpplearner
cpplearner

Reputation: 15908

In C++17 and later, you can use a fold-expression.

template <typename... CLASSES>
bool AreObjectsEqual(std::vector<A*>& vec)
{
    return std::all_of(vec.begin(), vec.end(),
        [](const auto v)
        {
            return (... || (dynamic_cast<CLASSES*>(v) != nullptr));
        });
}

In C++11 & 14, there's a somewhat obfuscated idiom.

template <typename... CLASSES>
bool AreObjectsEqual(std::vector<A*>& vec)
{
    return std::all_of(vec.begin(), vec.end(),
        [](const auto v)
        {
            bool retVal = false;
            using expand = int[];
            (void)expand{retVal = retVal || (dynamic_cast<CLASSES*>(v) != nullptr)...};
            return retVal;
        });
}

Upvotes: 1

Related Questions