2015-04-16 18 views
57
template< class T > 
class Foo { 
public: 
    Foo(T t) { } 
}; 

int main() { 
    int i = 0; 
    Foo f(i); 
} 

W powyższym kodzie kompilator skarży się, że argumenty szablonu nie występują przed "f". Rozumiem, że dedukowanie argumentów szablonu dla klasy z argumentów do konstruktora nie jest częścią standardu, ale moje pytanie brzmi: dlaczego? Czy kompilator nie ma wszystkich informacji, których potrzebuje do niejawnego utworzenia instancji Foo<int> i wywołania swojego konstruktora?Dlaczego konstruktorzy nie mogą wyprowadzać argumentów szablonu?

Zmieniano aby było jasne, że dzwonię z konstruktora z int (w przeciwieństwie do short, long, void* itp)

+2

Czy 0 to także 'bool' lub' char' lub wskaźnik? czy to tylko niejawna konwersja? – mstbaum

+2

Jeśli chodzi o problem praktyczny (nie dlatego), przy obecnym C++ wystarczy użyć funkcji fabrycznej. –

+2

@mstbaum: Wprawdzie nie jestem pewien, czy jest to istotne, ponieważ zamiar jest wyraźnie zgodny z tym samym argumentem odejmowania argumentów jako funkcji, gdzie wszystko to jest jasno określone. –

Odpowiedz

34

Ponieważ nikt nie określił, jak dokładnie to działa. Obecna propozycja do standardowego komitetu ma na celu sprawdzenie, czy działa. Zawiera też pewne trudności:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4471.html

Aktualizacja: Oto najnowsza wersja wniosku:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0091r0.html

+11

Dobrym pomysłem może być podsumowanie niektórych problemów z połączonego artykułu w samej odpowiedzi. Chociaż nie jest to odpowiedź wyłącznie na link, straciłaby ona wiele wartości, gdyby link się zawiesił. – IMSoP

+1

@IMSoP O ile masz rację, jeśli chodzi o uwzględnianie informacji, propozycje C++ nigdzie się nie ruszają w najbliższym czasie –

18

TL; DR: Template specjalizacji


Mogą, ale tylko argumenty szablonu dotyczące samej funkcji, a nie typu.

Deklaracja Foo f(0); jest nielegalna, ponieważ nie ma typu o nazwie Foo. Być może myśleli o

auto f = Foo(0); 

jednak, że nie jest dopuszczalne albo, ponieważ kompilator nie wie, czego szukać w zakres (istnieje nieskończony potencjał typy o nazwie Foo konstruktora i, ze specjalizacją, ewentualnie więcej niż jeden z konstruktora Foo(int))

zwykły sposób, aby to zrobić jest w funkcję fabryka pomocnika:

auto f = make_foo(0); 

gdzie fabryczne funkcja jest zwracany typ zależy od rodzaju odliczenia jej p arametry.


Można sobie wyobrazić, że funkcje fabryczne mogą być generowane automatycznie w zakresie przestrzeni nazw i stosowane reguły wtedy zwykle funkcja przeciążenia, ale to prowadzi do znacznej trudności, ponieważ nie może być szablon argumenty zarówno od rodzaju i samego konstruktora . Mogłyby one zostać po prostu połączone, z ograniczeniem, że wykluczyłoby to szablony klas z listami argumentów variadic, ponieważ nie byłoby sposobu na rozróżnienie, gdzie kończą się parametry typu i zaczynają się parametry funkcji.

8

Foo jest klasą szablon, a nie klasa. Jego typ zawsze musi być dostarczony w taki czy inny sposób, aby klasa była generowana z odpowiednimi typami. Nie można wykonać Foo, ponieważ Foo nie jest typem, ale jest to Foo<int>. To tworzy klasę tak:

class Foo { 
public: 
    Foo(int t) { } 
}; 

Jeśli tylko dostarczane Foo, kompilator nie wiedziałby jak wygenerować klasę.Foo<int> f(0) działa, ponieważ Foo<int> generuje klasę, zastępując T przez int. W typie, który wywołujesz konstruktor, kompilator wie już, że konstruktor akceptuje numer int.

+1

Dobra robota, przypominając ludziom, że szablon nie jest typem. (Pierwotnie użyłem "+1" zamiast dwóch pierwszych słów, ale widocznie to nie jest dozwolone) –

5

Nazwa klasy, która ma być utworzona, to Foo<int> (zgodnie z informacją).

Możliwe jest również napisanie Foo<short> f(0) lub Foo<unsigned long> f(0), lub Foo<Foo<double>*> f(0). W takich przypadkach nie oczekujesz jednak, że kompilator będzie w stanie odgadnąć typ, jeśli napiszesz tylko Foo f(0).

Można by sobie wyobrazić, że C++ mógłby zostały określone w przepisach, aby jakieś takie domysły w określony sposób (takich jak dosłowne 0 implikuje typ parametru int a nie innego), ale potem język byłby jeszcze więcej jest skomplikowana niż jest teraz, a dla innych użytkowników pojawiłyby się dodatkowe sposoby popełnienia błędów w programowaniu. Właściwie pisanie tego, co masz na myśli w takiej deklaracji, to: - wydaje się, że nie jest zbyt wiele do zapytania.

Edit: Po wysłaniu tego, zauważyłem w innej odpowiedzi, że nie jest propozycja, aby taką funkcję C++, rzeczywiście, jak można sobie wyobrazić.

+0

Jeśli zmieniłem instancję na 'int i = 0; Foo f (0); 'Kompilator powinien mieć wszystkie informacje potrzebne do utworzenia' Foo 'i wywołać jego contructor. Na podstawie powyższych odpowiedzi widzę jednak, dlaczego kompilator dostaje "Foo" i nie wie, co z nim zrobić i natychmiast zgłasza błąd. –

+0

Przepraszam, miałem na myśli 'int i = 0; Foo f (i); '. Zgadzam się co do tego, że byłoby to trudne do wdrożenia, po prostu chciałem lepiej zrozumieć dlaczego. –

+0

@wibs Dziękuję za wyjaśnienia, i odpowiednio zastępuję mój poprzedni komentarz. Pomysł, aby wywnioskować "Foo f (0)" z 'Foo f (i)' lub nawet 'Foo f (0)' nie jest _nierozsądny_ (zobacz proponowaną zmianę w języku wymienianym gdzie indziej), a mnie nawet można przekonać ostatecznie, że to dobry pomysł. Celem mojej odpowiedzi jest właśnie zasugerowanie, dlaczego rozsądne było również to, że nie została (jeszcze) dodana do specyfikacji językowej. –

Powiązane problemy