Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating over different types

Tags:

c++

c++11

c++14

Given the following code:

struct Window{
    void show();
    //stuff
}w1, w2, w3;

struct Widget{
    void show();
    //stuff
}w4, w5, w6;

struct Toolbar{
    void show();
    //stuff
}t1, t2, t3;

I want to show a bunch of items:

for (auto &obj : {w3, w4, w5, t1})
    obj.show();

However this does not compile since the std::initializer_list<T> in the for-loop cannot deduce T and in fact there is not really a T that would fit. I don't want to create a type erasure type because of the amount of code required and the unnecessary runtime overhead. How do I correctly write my loop so that the type of obj is deduced for every item in the conceptual list separately?

like image 949
nwp Avatar asked Dec 16 '15 14:12

nwp


People also ask

What is iterating over a list?

Iterator enables you to cycle through a collection, obtaining or removing elements. ListIterator extends Iterator to allow bidirectional traversal of a list and the modification of elements.

How to iterate through set?

Example 2: Iterate through Set using iterator() We have used the iterator() method to iterate over the set. Here, hasNext() - returns true if there is next element in the set. next() - returns the next element of the set.

Are iterators used in for each loops C++?

Working of the foreach loop in C++ So basically a for-each loop iterates over the elements of arrays, vectors, or any other data sets. It assigns the value of the current element to the variable iterator declared inside the loop.


3 Answers

In C++17 or better you'd use fold expressions, to "walk through" your heterogenous arguments applying the member function:

auto Printer = [](auto&&... args) {
    (args.show(), ...);
};

Printer(w1, w2, w3, w4, w5, w6, t1, t2, t3);

Demo

You can read more on this in my blog

like image 152
Nikos Athanasiou Avatar answered Oct 23 '22 15:10

Nikos Athanasiou


boost::fusion is awesome but oldskool - it caters for the deficiencies in c++03.

c++11's variadic template expansion to the rescue!

#include <iostream>

struct Window{
    void show() {
        std::cout << "Window\n";
    }
    //stuff
}w1, w2, w3;

struct Widget{
    void show() {
        std::cout << "Widget\n";
    }
    //stuff
}w4, w5, w6;

struct Toolbar{
    void show()
    {
        std::cout << "Toolbar\n";
    }
    //stuff
}t1, t2, t3;


template<class...Objects>
void call_show(Objects&&...objects)
{
    using expand = int[];
    (void) expand { 0, ((void)objects.show(), 0)... };
}

auto main() -> int
{
    call_show(w3, w4, w5, t1);
    return 0;
}

expected output:

Window
Widget
Widget
Toolbar

another, more generic way (requires c++14):

// note that i have avoided a function names that look like
// one in the standard library.

template<class Functor, class...Objects>
void for_all(Functor&& f, Objects&&... objects)
{
    using expand = int[];
    (void) expand { 0, (f(std::forward<Objects>(objects)), 0)... };

}

called like so:

for_all([](auto& thing) { thing.show(); }, w3, w4, w5, t1);
like image 39
Richard Hodges Avatar answered Oct 23 '22 15:10

Richard Hodges


Another option is to use boost::tuple or std::tuple and boost::fusion::for_each algorithm:

#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/adapted/boost_tuple.hpp>

boost::fusion::for_each(
    boost::tie(w1, w2, w3, w4, w5, w6, t1, t2, t3), // by reference, not a copy
    [](auto&& t) { t.show(); } 
    );

Just out of curiosity, compared the generated assembly output of Richard Hodges's method with the above. With gcc-4.9.2 -Wall -Wextra -std=gnu++14 -O3 -march=native the produced assembly code is identical.

like image 21
Maxim Egorushkin Avatar answered Oct 23 '22 16:10

Maxim Egorushkin