2014-11-07 12 views
5

Compilare il seguente codice con clang 3.5.0 e gcc 4.9.1 restituisce un errore nell'ultima istruzione.Perché la bretella-init-list si comporta diversamente in una chiamata di funzione rispetto a una chiamata del costruttore?

#include <iostream> 

struct Foo { Foo(int x, int y) { std::cout << "Foo(int = " << x << ", int = " << y << ")" << std::endl; } }; 

void bar(int x, int y) { std::cout << "bar(int = " << x << ", int = " << y << ")" << std::endl; } 

int main() 
{ 
    Foo({}, {}); // Foo(int = 0, int = 0) 
    Foo({1}, {2}); // Foo(int = 1, int = 2) 
    Foo({1, 2}); // Foo(int = 1, int = 2) 

    bar({}, {}); // bar(int = 0, int = 0) 
    bar({1}, {2}); // bar(int = 1, int = 2) 
    bar({1, 2}); // error: no matching function for call to 'bar' <<< Why? <<< 
} 

Perché Foo({1, 2}) bene mentre bar({1, 2}) non lo è?

In particolare, sarebbe bello conoscere la logica.

+3

La mia ipotesi è, 'Foo ({1,2})' crea un oggetto Foo temporanea e chiama il ctor copia . – Borgleader

+0

@Borgleader Grazie, ha senso! :-) – precarious

+0

Il commento di @Borgleader è corretto - con {1, 2} puoi creare un oggetto Foo temporaneo, ma solo quando è previsto Foo. In realtà non è possibile passare più parametri per funzionare con quello. –

risposta

6

Foo({1,2}) crea un oggetto Foo temporaneo e chiama il costruttore di copie.

Vedi questo esempio modificato con costruttore di copia eliminare: http://coliru.stacked-crooked.com/a/6cb80746a8479799

errori It con:

main.cpp:6:5: note: candidate constructor has been explicitly deleted 
    Foo(const Foo& f) = delete; 
+0

Ma non era un costruttore di copie generato implicitamente nell'esempio originale? Perché eliminarlo e causare un altro motivo per non compilare? Questo non spiega perché 'bar' non può essere chiamato; ed è tutto sugli argomenti di bar, vedi questo [modo di fissare la compilazione] (http://coliru.stacked-crooked.com/a/2b8f6fee6244c251) –

+0

@NorahAttkins Hai perso il punto. Il punto era, l'elenco di inizializzazione non passava i 2 inti al costruttore (che l'OP assumeva, e si chiedeva perché non avrebbe funzionato in una chiamata di funzione che richiede anche 2 ints), sta generando un oggetto temporaneo e chiamando il copia costruttore. L'eliminazione ha mostrato che il costruttore della copia veniva chiamato. – Borgleader

+0

No, non lo ha fatto; Guarda questo [esempio] (http://coliru.stacked-crooked.com/a/7314848093d2987a) Se rimuovo la chiamata a 'Foo ({1, 2})' il programma non riesce ancora a compilare quando chiama 'bar' senza mai menzionare qualcosa sui costruttori di copie cancellate. La chiamata a 'bar' non ha mai creato un oggetto' Foo' temporaneo –

1

La linea

bar({1, 2}); 

passa effettivamente in funzione bar, un oggetto temporaneo di digitare

<brace-enclosed initializer list> // it's made clear in the comments that brace initializers have no type 

e non esiste alcun modo per convertire questo oggetto temporaneo al tipo del primo argomento che è un int. Così il error

non può convertire <brace-enclosed initializer list> a int per argomento 1 a

void bar(int, int) 
+0

No, non è corretto. Una lista di inizializzazione rinforzata non ha un tipo. – Columbo

+0

@Columbo Sei [sicuro] (http://coliru.stacked-crooked.com/a/7dbfd72283b52c55)? –

+1

@NorahAttkins [Un inizializzatore rinforzato non ha tipo] (http://www.youtube.com/watch?v=wQxj20X-tIU&list=UUMlGfpWw-RUdWX_JbLCukXg#t=1792) – Borgleader