2013-07-10 13 views
14

Rozumiem, że, biorąc pod uwagę usztywnione inicjator, auto będzie wydedukować rodzaj std::initializer_list, natomiast typ szablonu odliczenie zawiedzie:Dlaczego odliczanie typu auto i szablon różnią się w przypadku inicjatorów ze stężeniem?

auto var = { 1, 2, 3 }; // type deduced as std::initializer_list<int> 

template<class T> void f(T parameter); 

f({ 1, 2, 3 });   // doesn't compile; type deduction fails 

ja nawet wiem, gdzie to jest określone w standardzie C++ 11: 14.8. 2,5/5 punkt 5:

[It's a non-deduced context if the program has] A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list type. [ Example:

template void g(T);

g({1,2,3}); // error: no argument deduced for T

end example ]

Co nie wiem, czy rozumiem dlaczego ta różnica w zachowaniu typu odliczenia istnieje. Specyfikacja na CD C++ 14 jest taka sama jak w C++ 11, więc przypuszczalnie komitet normalizacyjny nie postrzega zachowania C++ 11 jako defektu.

Czy ktoś wie, dlaczego auto wnioskuje o typ zbędnego inicjatora, ale szablony nie są dozwolone? Podczas gdy spekulatywne wyjaśnienia dotyczące formy "może to być powodem" są interesujące, szczególnie interesują mnie wyjaśnienia osób, dla których standard został napisany tak, jak był.

+0

Było jeszcze jedno pytanie zadane przez SO na temat tego, co wymyśliłeś. Może mieć w tym jakiś powód. – chris

+2

Ok, znalazłem. Jedynym powodem, dla którego dyskusja jest jednym komentarzem, możesz rzucić okiem: http://stackoverflow.com/questions/17496268/type-inference-with-rvalue-initializer-list – chris

+3

Cytat z [Scott Meyers] (http: // /scottmeyers.blogspot.cz/2013/07/when-decltype-meets-auto.html): "* Nie mam pojęcia, dlaczego dedukcja typu dla' auto' i dla szablonów nie jest identyczna. Jeśli wiesz, proszę powiedz mi! * ". –

Odpowiedz

0

Przede wszystkim jest to "spekulacyjne wyjaśnienie formy" może to być powód "" jak to nazywasz.

{1,2,3} to nie tylko std::initializer_list<int>, ale pozwala również na inicjowanie typów bez konstruktora. Na przykład:

#include <initializer_list> 

struct x{ 
    int a,b,c; 
}; 

void f(x){ 

} 
int main() { 
    f({1,2,3}); 
} 

to poprawny kod. Aby pokazać, że nie jest initializer_list zobaczymy następujący kod:

#include <initializer_list> 

struct x{int a,b,c;}; 

void f(x){ 

} 
int main() { 
    auto il = {1, 2, 3}; 
    f(il); 
} 

Błąd brzmi: „Jaka jest różnica”

prog.cpp: In function ‘int main()’: 
prog.cpp:10:9: error: could not convert ‘il’ from ‘std::initializer_list<int>’ to ‘x’ 

A teraz do pytania

w kodzie auto x = {1, 2, 3}; to OK, aby określić typ, ponieważ koder wyraźnie powiedział: „To nie jest ważne jaki typ jest” za pomocą auto

O ile w przypadku szablonu funkcja może być pewny, że używa innego typu. I dobrze jest zapobiegać błędom w niejednoznacznych przypadkach (nie wygląda na styl C++, przez).

Szczególnie źle będzie na wypadek, gdyby istniała jedna funkcja f(x), a następnie została zmieniona na pierwszą. Programista napisał, aby użyć go jako x, a po dodaniu nowej funkcji dla innego typu zmienia się nieznacznie, aby wywołać zupełnie inną.

+1

Nie rozumiem, jak mówienie "auto" oznacza "nie jest ważne, jaki jest typ", ale "szablon " oznacza coś innego. W obu przypadkach ryzykujesz, że typ wydedukowany może nie być tym, co zamierzał programista. – KnowItAllWannabe

+0

Nie rozumiem drugiego kodu. Napisałeś "Aby pokazać, że to nie jest lista inicjalizująca", ale w przykładzie '{1,2,3}' jest lista inicjalizacyjna, stąd błąd ... – user463035818

+0

Mam na myśli to, że pokazuję, że w pierwszym kodzie nie jest to initializer_list. Ponieważ kiedy jest to initialzer_list, to nie działa – RiaD

13

Istnieją dwa ważne powody, dla szablonów nie robić żadnych odliczenia (dwa że pamiętam w dyskusji z człowiekiem odpowiedzialnym za)

  • Obawy przyszłych rozszerzeń języka (istnieje wiele znaczeń mogłeś wymyślić - co by było, gdybyśmy chcieli wprowadzić perfekcyjne przekazywanie argumentów dla spreparowanych argumentów funkcji init?)

  • Nawiasy mogą czasami skutecznie zainicjować parametru funkcji, która jest zależna

template<typename T> 
void assign(T &d, const T& s); 
int main() { 
    vector<int> v; 
    assign(v, { 1, 2, 3 }); 
} 

Jeśli T byłoby wywnioskować z prawej strony do initializer_list<int> ale po lewej stronie do vector<int>, to nie zadziałałoby z powodu sprzecznego argumentu.

Odliczenie za auto na initializer_list<T> jest kontrowersyjne. Istnieje propozycja C++ - po 14, aby go usunąć (i zablokować inicjalizację za pomocą { } lub {a, b}, i aby {a} wydedukować na typ a).

Powiązane problemy