samedi 29 août 2015

Seeking compile-time formula for many specializations

Is there a way to write

template <int> struct Map;
template <> struct Map<0> { using type = index_sequence<0>; };
template <> struct Map<1> { using type = index_sequence<1>; };
template <> struct Map<2> { using type = index_sequence<2>; };
template <> struct Map<3> { using type = index_sequence<0,1>; };
template <> struct Map<4> { using type = index_sequence<0,2>; };
template <> struct Map<5> { using type = index_sequence<1,2>; };
template <> struct Map<6> { using type = index_sequence<0,1,2>; };

as one single unspecialized template?

template <int N> struct Map {
    using type = index_sequence<???>;
};

Here the int template arguments shall always be listed in increasing order and can only have values 0, 1,..., MAX. The case for MAX == 2 is the example above. How to write the above for any value of MAX?

In case you are wondering, this example usage is a motivation for the solution:

#include <iostream>
#include <array>
#include <list>

class Base {
    public:  virtual ~Base() = default;
};

template <int...>  // The ints shall always be listed in increasing order and have values 0, 1, or 2.
class Derived : public Base {};

std::array<std::list<Base*>, 7> groups;

template <int...> struct index_sequence {};

template <int> struct Map;
template <> struct Map<0> { using type = index_sequence<0>; };
template <> struct Map<1> { using type = index_sequence<1>; };
template <> struct Map<2> { using type = index_sequence<2>; };
template <> struct Map<3> { using type = index_sequence<0,1>; };
template <> struct Map<4> { using type = index_sequence<0,2>; };
template <> struct Map<5> { using type = index_sequence<1,2>; };
template <> struct Map<6> { using type = index_sequence<0,1,2>; };

template <int... Is>
bool isDerivedType (const index_sequence<Is...>&, Base* base) {
    return dynamic_cast<Derived<Is...>*>(base) != nullptr;
}

template <int N>
void checkTypes (Base* base, std::array<std::list<Base*>, 7>& array) {
    if (isDerivedType(typename Map<N>::type{}, base))
        groups[N].push_back(base);
    else
        checkTypes<N+1>(base, array);   
}

template <>
void checkTypes<7> (Base*, std::array<std::list<Base*>, 7>&) {}  // End of recursion

int main() {
    const std::list<Base*> list = {new Derived<0>, new Derived<1,2>, new Derived<0,2>, new Derived<1>, new Derived<1,2>, new Derived<0>, new Derived<0,1,2>, new Derived<0,1>, new Derived<1,2>, new Derived<2>, new Derived<2>, new Derived<0>, new Derived<0,2>};
    for (Base* x : list)
        checkTypes<0>(x, groups);
    for (int i = 0; i < 7; i++) {
        std::cout << "Group " << i << ": ";
        for (const Base* x : groups[i])
            std::cout << x << "  ";
        std::cout << '\n';
    }
}

/*
Output:

Group 0: 0x6e13f0  0x6e1940  0x6e5d80
Group 1: 0x6e1900
Group 2: 0x6e5dd0  0x6e5d60
Group 3: 0x6e5e40
Group 4: 0x6e18e0  0x6e5d70
Group 5: 0x6e1440  0x6e1920  0x6e5db0
Group 6: 0x6e1960
*/

Aucun commentaire:

Enregistrer un commentaire