C++ Iterazione su un pacchetto di parametri


Esempio

Spesso, è necessario eseguire un'operazione su ogni elemento di un pacchetto di parametri modello variadic. Ci sono molti modi per farlo e le soluzioni diventano più facili da leggere e scrivere con C ++ 17. Supponiamo di voler semplicemente stampare ogni elemento in un pacchetto. La soluzione più semplice è recitare:

C ++ 11
void print_all(std::ostream& os) {
    // base case
}

template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
    os << first;
    
    print_all(os, rest...);
}

Potremmo invece utilizzare il trucco di espansione, per eseguire tutto lo streaming in una singola funzione. Questo ha il vantaggio di non aver bisogno di un secondo sovraccarico, ma ha lo svantaggio di una lettura inferiore a quella stellare:

C ++ 11
template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
    using expander = int[];
    (void)expander{0,
        (void(os << args), 0)...
    };
}

Per una spiegazione di come funziona, vedi l'eccellente risposta di TC .

C ++ 17

Con C ++ 17, otteniamo due potenti nuovi strumenti nel nostro arsenale per risolvere questo problema. Il primo è un'espressione di piegatura:

template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
    ((os << args), ...);
}

E il secondo è if constexpr , che ci consente di scrivere la nostra soluzione ricorsiva originale in una singola funzione:

template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
    os << first;

    if constexpr (sizeof...(rest) > 0) {        
        // this line will only be instantiated if there are further
        // arguments. if rest... is empty, there will be no call to
        // print_all(os). 
        print_all(os, rest...);
    }
}