Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over base classes of variadic template class

How can I iterate over all base classes of a variadic template class and call a function for each of them.

Here is a minimal example:

struct A { void foo() { std::cout << "A" << std::endl; } };
struct B { void foo() { std::cout << "B" << std::endl; } };
struct C { void foo() { std::cout << "C" << std::endl; } };

template<typename... U>
struct X : public U...
{
    void foo() {
        static_cast<U*>(this)->foo()...; // ??? should call `foo` for all `U`
    }
};

int main() {
    X<A,B,C> x;
    x.foo();
}
like image 731
Danvil Avatar asked May 04 '14 23:05

Danvil


2 Answers

You can't normally without C++17's fold expressions. The ellipsis going there is not valid and the ellipsis going after the asterisk would create a list of pointer template arguments. For the appropriate pattern to be repeated, the ellipsis would have to be at the end of the statement, and that doesn't work here. I found this article to be a good resource for pack expansion.

Instead, there is a trick for it that doesn't require building up any recursive things:

int arr[] = {(static_cast<U*>(this)->foo(), 0)...};

This calls each function and then uses the result with the comma operator to produce the needed ints. Unfortunately, this might result in an unused variable warning. One minimal way around this is to use a std::array (or some class that can be initialized with an initializer list) and cast the result of creating an unnamed one of those to void (casting to void being a somewhat common technique for preventing the warning in general).

like image 105
chris Avatar answered Nov 12 '22 10:11

chris


Here is a way:

struct thru{template<typename... A> thru(A&&...) {}};

struct A { void foo() { std::cout << "A" << std::endl; } };
struct B { void foo() { std::cout << "B" << std::endl; } };
struct C { void foo() { std::cout << "C" << std::endl; } };

template<typename... U>
struct X : public U...
{
    void foo() { thru{(U::foo(), 0)...}; }
};

But if you care about the order of calls, watch out for the known gcc bug as discussed here.

like image 35
iavr Avatar answered Nov 12 '22 12:11

iavr