Se da argomenti variadic intendi i puntini di sospensione (come in void foo(...)
), poi quelli sono fatti più o meno obsoleti dalla modelli variadic piuttosto che dalle liste di inizializzazione - c'è ancora potrebbero essere alcuni casi di utilizzo per le ellissi quando si lavora con SFINAE per implementare (per esempio) i tratti del tipo, o per la compatibilità C, ma parlerò dei casi d'uso ordinari qui.
modelli variadic, infatti, consentono di tipi differenti per il pacco argomento (infatti, qualsiasi tipo), mentre i valori di una lista di inizializzazione devono essere convertibile tipo sottostante dell'elenco initalizer (e restringimento di conversione sono non consentito):
#include <utility>
template<typename... Ts>
void foo(Ts...) { }
template<typename T>
void bar(std::initializer_list<T>) { }
int main()
{
foo("Hello World!", 3.14, 42); // OK
bar({"Hello World!", 3.14, 42}); // ERROR! Cannot deduce T
}
a causa di questo, le liste di inizializzazione sono meno spesso utilizzati quando è richiesto il tipo deduzione, a meno che il tipo degli argomenti è infatti destinata ad essere omogenea. I modelli Variadic, d'altra parte, forniscono una versione di tipo sicura da tipo dell'elenco di variabili variabili di ellissi.
Inoltre, il richiamo di una funzione che richiede un elenco di inizializzazione richiede di racchiudere gli argomenti in una coppia di parentesi, che non è il caso di una funzione che accetta un pacchetto di argomenti variadic.
Infine (beh, ci sono altre differenze, ma queste sono più rilevanti per la tua domanda), i valori in una lista di inizializzatori sono oggetti const
. Per Paragrafo 18,9/1 della C++ 11 standard:
Un oggetto di tipo initializer_list<E>
fornisce accesso ad un array di oggetti di tipo const E
. [...] La copia di un elenco di inizializzazione fa sì che non copi gli elementi sottostanti. [...]
Ciò significa che, sebbene i tipi non copiabili possano essere spostati in un elenco di inizializzatori, non possono essere spostati da esso. Questa limitazione può o non può soddisfare i requisiti di un programma, ma generalmente rende gli elenchi di inizializzatori una scelta limitante per contenere tipi non copiabili.
Più in generale, comunque, quando si utilizza un oggetto come elemento di un elenco di inizializzazione, ne faremo una copia (se è un lvalue) o lo spostiamo (se è un valore):
#include <utility>
#include <iostream>
struct X
{
X() { }
X(X const &x) { std::cout << "X(const&)" << std::endl; }
X(X&&) { std::cout << "X(X&&)" << std::endl; }
};
void foo(std::initializer_list<X> const& l) { }
int main()
{
X x, y, z, w;
foo({x, y, z, std::move(w)}); // Will print "X(X const&)" three times
// and "X(X&&)" once
}
In altre parole, elenchi di inizializzazione non può essere utilizzato per passare gli argomenti di riferimento (*), per non parlare eseguendo inoltro perfetto:
template<typename... Ts>
void bar(Ts&&... args)
{
std::cout << "bar(Ts&&...)" << std::endl;
// Possibly do perfect forwarding here and pass the
// arguments to another function...
}
int main()
{
X x, y, z, w;
bar(x, y, z, std::move(w)); // Will only print "bar(Ts&&...)"
}
(*) Si deve notare, tuttavia, quello initializer lists (unlike all other containers of the C++ Standard Library) do have reference semantics, quindi anche se una copia/spostamento degli elementi viene eseguita quando si inseriscono elementi in un elenco di inizializzazione, la copia dell'elenco di inizializzazione non causerà alcuna copia/spostamento degli oggetti contenuti (come menzionato nel paragrafo della norma citata sopra) :
int main()
{
X x, y, z, w;
auto l1 = {x, y, z, std::move(w)}; // Will print "X(X const&)" three times
// and "X(X&&)" once
auto l2 = l1; // Will print nothing
}
Gli elenchi di inizializzatori possono avere solo un tipo. Tieni presente che ci sono modelli variadici, a differenza degli argomenti variati C non di tipo sicuro. – chris
@chris: Ed è anche un peccato. :( – GManNickG
@GManNickG, Sì, 'std :: tuple' incorporato nelle liste di inizializzazione sarebbe bello, ma ci sono indubbiamente cose che sarebbero difficili da risolvere che non riesco a pensare proprio adesso. – chris