迭代不同的types

给出以下代码:

struct Window{ void show(); //stuff }w1, w2, w3; struct Widget{ void show(); //stuff }w4, w5, w6; struct Toolbar{ void show(); //stuff }t1, t2, t3; 

我想show一堆物品:

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

然而,这不能编译,因为for循环中的std::initializer_list<T>不能推导出T ,事实上也没有真正适合的T 我不想创build一个types擦除types,因为所需的代码量和不必要的运行时间开销。 我该如何正确编写我的循环,以便为概念列表中的每个项目分别推导出obj的types?

在现代的C ++中,你会使用foldexpression式来“遍历”应用成员函数的异类参数:

 auto Printer = [](auto&&... args) { (args.show(), ...); }; Printer(w1, w2, w3, w4, w5, w6, t1, t2, t3); 

演示

你可以在我的博客上阅读更多

boost :: fusion是很棒的,但是oldskool – 它迎合了c ++ 03的缺陷。

C ++ 11的可变模板扩展到救援!

 #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; } 

预期产出:

 Window Widget Widget Toolbar 

另一种更通用的方式(需要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)... }; } 

这样叫:

 for_all([](auto& thing) { thing.show(); }, w3, w4, w5, t1); 

另一种select是使用boost::tuplestd::tupleboost::fusion::for_eachalgorithm:

 #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(); } ); 

出于好奇,把Richard Hodges方法生成的assembly输出与上面的方法进行比较。 用gcc-4.9.2 -Wall -Wextra -std=gnu++14 -O3 -march=native生成的汇编代码是相同的。

基于https://stackoverflow.com/a/6894436/3484570这工作没有创build一个额外的function,提升或inheritance。;

标题:

 #include <tuple> #include <utility> template<std::size_t I = 0, typename FuncT, typename... Tp> inline typename std::enable_if<I == sizeof...(Tp), void>::type for_each(const std::tuple<Tp...> &, FuncT) // Unused arguments are given no names. { } template<std::size_t I = 0, typename FuncT, typename... Tp> inline typename std::enable_if<I < sizeof...(Tp), void>::type for_each(const std::tuple<Tp...>& t, FuncT f) { f(std::get<I>(t)); for_each<I + 1, FuncT, Tp...>(t, f); } template<std::size_t I = 0, typename FuncT, typename... Tp> inline typename std::enable_if<I == sizeof...(Tp), void>::type for_each(std::tuple<Tp...> &&, FuncT) // Unused arguments are given no names. { } template<std::size_t I = 0, typename FuncT, typename... Tp> inline typename std::enable_if<I < sizeof...(Tp), void>::type for_each(std::tuple<Tp...>&& t, FuncT f) { f(std::get<I>(t)); for_each<I + 1, FuncT, Tp...>(std::move(t), f); } 

的.cpp:

 struct Window{ void show(){} //stuff }w1, w2, w3; struct Widget{ void show(){} //stuff }w4, w5, w6; struct Toolbar{ void show(){} //stuff }t1, t2, t3; int main() { for_each(std::tie(w3, w4, w5, t1), [](auto &obj){ obj.show(); }); } 

WindowWidgetToolbar共享公共接口,所以你可以创build抽象类并使其他类inheritance它:

 struct Showable { virtual void show() = 0; // abstract method }; struct Window: Showable{ void show(); //stuff }w1, w2, w3; struct Widget: Showable{ void show(); //stuff }w4, w5, w6; struct Toolbar: Showable{ void show(); //stuff }t1, t2, t3; 

然后,您可以创build指向Showable的指针数组,并遍历它:

 int main() { Showable *items[] = {&w3, &w4, &w5, &t1}; for (auto &obj : items) obj->show(); } 

看到它在线工作

我build议Boost.Hana ,其中恕我直言,是最好的和最灵活的模板元编程库可用。

 #include <boost/hana/ext/std/tuple.hpp> #include <boost/hana.hpp> namespace hana = boost::hana; hana::for_each(std::tie(w3, w4, w5, t1), [](auto& obj) { obj.show(); }); 

我认为boost::variant值得一提。 所有更多的机会成为std::variant在C + + 17。

 int main() { std::vector<boost::variant<Window*, Widget*, Toolbar*>> items = { &w1, &w4, &t1 }; for (const auto& item : items) { boost::apply_visitor([](auto* v) { v->show(); }, item); } return 0; } 

一个迟到的答案,但这里是通用的解决scheme与C + + 14的工作就像boost::fusion::for_each但不需要Boost:

 #include <tuple> namespace detail { template<typename Tuple, typename Function, std::size_t... Is> void tuple_for_each_impl(Tuple&& tup, Function&& fn, std::index_sequence<Is...>) { using dummy = int[]; static_cast<void>(dummy { 0, (static_cast<void>(fn(std::get<Is>(std::forward<Tuple>(tup)))), 0)... }); } } template<typename Function, typename... Args> void tuple_for_each(std::tuple<Args...>&& tup, Function&& fn) { detail::tuple_for_each_impl(std::forward<std::tuple<Args...>>(tup), std::forward<Function>(fn), std::index_sequence_for<Args...>{}); } int main() { tuple_for_each(std::tie(w1, w2, w3, w4, w5, w6, t1, t2, t3), [](auto&& arg) { arg.show(); }); } 

如果你想在不使用std::tuple的情况下实现更多或更less的function,可以创build上述代码的单一函数变体:

 #include <utility> template<typename Function, typename... Args> void va_for_each(Function&& fn, Args&&... args) { using dummy = int[]; static_cast<void>(dummy { 0, (static_cast<void>(fn(std::forward<Args>(args))), 0)... }); } int main() { auto action = [](auto&& arg) { arg.show(); }; va_for_each(action, w1, w2, w3, w4, w5, w6, t1, t2, t3); } 

第二个例子的缺点是它需要先指定处理函数,因此不像众所周知的std::for_each 。 无论如何,用我的编译器(GCC 5.4.0)使用-O2优化级别,他们产生相同的汇编输出 。