template<class...Fs>
void do_in_order(Fs&&...fs) {
int _[]={0, (std::forward<Fs>(fs)(), void(), 0)...};
(void)_;
}
ukrywa Składnia wymagana do wykonania pakietu obiektów funkcyjnych w kolejności od lewej do prawej.
Następnie:
struct Bar {
template <class... Ts>
void foo() {
do_in_order([&]{
using T = Ts;
// code
}...);
}
};
iw zgodnego kompilatora, będziemy uruchomić // code
z T
bycia każdego typu od lewej do prawej.
Należy pamiętać, że niektóre kompilatory podające się za kompilatory C++ 11 mogą nie skompilować powyższego.
Zaletą tej techniki jest ukrywanie nieprzyjemnego "rozszerzenia i oceny szablonów" w ramach funkcji o jednoznacznej nazwie. Raz piszesz: do_in_order
i zwykle wystarcza prawie na każde użycie tej sztuczki z rozszerzeniem macierzy.
Istnieją dwa ważne powody używania tego rodzaju ezoterycznej składni zamiast "bardziej prostych" rozwiązań rekursywnych.
Po pierwsze, ułatwia to optymalizatorowi. Optymalizatory czasami rezygnują po stosie wywołań rekursywnych.
Po drugie, suma nazw długości znaków funkcji dla tradycyjnych funkcji rekursywnych rośnie w O (n^2). Jeśli używasz typów pomocniczych, całkowita długość nazw jest również równa O (n^2). O ile nie jesteś ostrożny, może to spowodować kompilację czasu, wydłużenie czasu połączenia i zwiększenie rozmiaru binarnego.
W C++ 1z planuje się składnię, która może sprawić, że ezoteryczne części powyższego będą mniej ezoteryczne.
huh? 'foo' nie przyjmuje argumentów. – MadScientist
Jako wadę, wymaga N rekursywnych kroków dla typów N i tworzy instancje typów i funkcji, których długość nazwy wynosi O (N^2). Wykonanie powyższego z N skromnie dużym powoduje powolną kompilację i może prowadzić do binarnego wzdęcia, jeśli te nazwy nie zostaną usunięte przez kompilator. – Yakk