0

I want to find all objects of given types and add them to vector. For now I have code:

template<class T>
void fill1(std::vector<Character*> &vec2)
{
    for (int i = 0; i < GameObject::allObjects.size(); i++)
    {
         if (dynamic_cast<T>(GameObject::allObjects[i]))
         {
             vec2.push_back(dynamic_cast<Character*>(GameObject::allObjects[i]));
         }
    }
}

 template<class First, class ...T>
 void fill2(std::vector<Character*> &vec2) 
 {
     fill1<First>(vec2);
     fill2<T...>(vec2);
 }

 template<class ... T>
 std::vector<Character*> SpecialList<T...>::get()
 {
      std::vector<Character*> vec2;
      fill2<T...>(vec2);
      return vec2;
 }

The code doesn't compile at all. The error we are getting is: could not deduce template argument for 'First'

I know that all the given types are inherited from class Character and I have a vector of all my objects (GameObject::allObjects).

  • 1
    To nudge you in the right direction: What do you expect to happen when `fill2(vec2);` is invoked when `T` is an empty type list? – cdhowie Jun 01 '17 at 15:45
  • The problem is I don't really understand. I was hoping that it will end if there are no arguments to get. I don't know how to check if there are any. – Radosław Panuszewski Jun 01 '17 at 15:53
  • Well, you can't instantiate `fill2()` without at least one template argument: `First`. – cdhowie Jun 01 '17 at 17:46

1 Answers1

0

Instead of recursion use parameter pack expansion inside list initialization of a dummy array e.g.:

#include <vector>
#include <memory>
#include <tuple>
#include <iostream>
#include <algorithm>

template <class... Ts>
struct tag { };

template <class T>
struct Predicate {
    template <class U>
    bool operator()(std::shared_ptr<U> sp) const {
        return std::dynamic_pointer_cast<T>(sp) != nullptr;
    }
};

template <class... Ts, class T>
std::vector<std::shared_ptr<T>> all(std::vector<std::shared_ptr<T>> &v, tag<Ts...>) {
    std::vector<std::shared_ptr<T>> result;
    int dummy[] {(std::copy_if(v.begin(), v.end(), std::back_inserter(result), Predicate<Ts>{}),0)...};
    static_cast<void>(dummy);
    return result;
}

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

struct B: A { };
struct C: A { };

int main() {
    std::vector<std::shared_ptr<A>> v { std::make_shared<A>(), 
                                        std::make_shared<A>(), 
                                        std::make_shared<B>(), 
                                        std::make_shared<B>(), 
                                        std::make_shared<C>(), 
                                        std::make_shared<C>() };

    std::cout << all(v, tag<B, C>{}).size() << std::endl;
}

[live demo]

W.F.
  • 13,888
  • 2
  • 34
  • 81
  • Beware that when using parameter expansion, the standard does not mandate in what order the expanded expressions are evaluated. – cdhowie Jun 01 '17 at 20:55
  • @cdhowie you're mixing up parameter expansion with expression evaluation order... In my example I expanded parameter pack inside initializer list. This, after expansion, would look more or less like this: `int dummy[] = {Ex1, Ex2, ..., ExN}; `. Order of evaluation of such expressions is very well defined by c++ standard (left-to-right). You can read more about it [here](https://stackoverflow.com/a/14443030/4324224). You probably though about evaluation of expression passed as a function parameters which are implementation defined... – W.F. Jun 02 '17 at 09:18