Domyślne argumenty szablonu

151

Jeśli wolno mi wykonywać następujące czynności:

template <typename T = int>
class Foo{
};

Dlaczego w zasadzie nie wolno mi wykonywać następujących czynności?

Foo me;

Ale muszę określić co następuje:

Foo<int> me;

C ++ 11 wprowadził domyślne argumenty szablonów i obecnie są one nieuchwytne dla mojego pełnego zrozumienia.

user633658
źródło

Odpowiedzi:

188

Musisz zrobić:

Foo<> me;

Argumenty szablonu muszą być obecne, ale możesz pozostawić je puste.

Pomyśl o tym jak o funkcji fooz jednym domyślnym argumentem. Wyrażenie footego nie nazwie, ale foo()będzie. Składnia argumentów musi nadal istnieć. Jest to zgodne z tym.

Joseph Mansfield
źródło
4
@Pubby Przypuszczam byłoby utworzyć kilka niepotrzebnych komplikacji, jeśli Foo może być identyfikatorem szablon lub może być jawne instancji w zależności od tego, czy istnieje domyślny argument. Lepiej zachowaj jawną składnię tworzenia instancji. Pomyśl o tym jak o funkcji fooz jednym domyślnym parametrem. Nie możesz tego tak foonazwać, nazywasz to foo(). Zachowanie tej spójności ma sens.
Joseph Mansfield,
2
@sftrabbit, ale nie możesz wywołać funkcji bez argumentów, takich jak fooobie; możesz nazwać klasę bez argumentów, jak Foojednak.
Seth Carnegie
4
@aschepler W przypadku funkcji argumenty szablonu można wywnioskować z argumentów funkcji. W przypadku klasy nie można zdecydować, czy chodziło Ci o klasę szablonu z domyślnymi argumentami, czy też o klasę bez szablonu.
Olaf Dietsche
21
@OlafDietsche, ale nie możesz mieć klasy szablonu i klasy innej niż szablonowa o tej samej nazwie, więc kompilator powinien być w stanie zdecydować, po prostu patrząc, jaka to nazwa.
Seth Carnegie
7
@Pubby Chyba komisja standardowa zadała sobie to samo. Teraz, z C ++ 17, <>nie jest już potrzebne w tym przypadku. Sprawdź moją odpowiedź, aby uzyskać więcej informacji.
Paolo M
53

Z C ++ 17 rzeczywiście możesz.

Ta funkcja nosi nazwę dedukcji argumentów z szablonu klasy i zapewnia większą elastyczność w sposobie deklarowania zmiennych typu szablonowego .

Więc,

template <typename T = int>
class Foo{};

int main() {
    Foo f;
}

jest teraz legalnym kodem C ++ .

Paolo M.
źródło
5
Dziwne. Właśnie wypróbowałem to w moim projekcie C ++ 17 i nie zadziałało: „typ symbolu zastępczego szablonu„ const MyType ”musi następować po prostym identyfikatorze deklaratora”. Używam GCC 7.3.0.
Silicomancer
1
@Silicomancer Trudno powiedzieć, nie widząc twojego kodu i wiersza poleceń ... Może masz do czynienia ze wskazówkami, jak tutaj ?
Paolo M
1
Wydaje się, że Clang nie akceptuje tego? coliru.stacked-crooked.com/a/c5d3c0f90ed263c2
Borgleader
1
@Borgleader Najwyraźniej Coliru używa clang 5.0. Sądząc po tym , powinien obsługiwać dedukcję argumentów z szablonu w C ++ 17, ale najwyraźniej id nie. Jeśli wypróbujesz ten sam przykład w Wandbox, używając Clang 7.0, działa bezbłędnie.
Paolo M
2
@PaoloM Och super, cieszę się, że to tylko problem z wersją kompilatora. Dzięki za przyjrzenie się temu.
Borgleader
19

Nie możesz tego zrobić, ale możesz to zrobić

typedef Foo<> Fooo;

a potem zrób

Fooo me;
g24l
źródło
czy jest jakaś różnica w tym z typem domyślnym i:, typedef Foo<float> Fooo;bez typu domyślnego?
qrikko
5
11-owym sposobem C ++ byłoby powiedziećusing Fooo = Foo<>;
Adrian W
18

Możesz użyć następujących:

Foo<> me;

I intniech to będzie twój argument szablonowy. Wsporniki kątowe są konieczne i nie można ich pominąć.

Andy Prowl
źródło
To ma sens i dziękuję, ale, jak zauważono poniżej, dlaczego określony typ nie występuje?
user633658
@ user633658: Czy chodziło Ci o „specyfikator typu”? Nie jestem pewien, czy rozumiem
Andy Prowl
W każdym razie, jeśli chodzi o powód, dla którego potrzebne są puste nawiasy kątowe, mogę tylko przypuszczać, a one polegają na wykluczeniu ewentualnych niejasności przy użyciu samej nazwy szablonu, ale muszę przyznać, że nie znam dokładnego powód
Andy Prowl
Podejrzewam, że wymaganiem dla <> jest umożliwienie parserowi kompilatora określenia, że ​​odwołujesz się do klasy opartej na szablonie o nazwie foo, a nie do czegoś innego o nazwie foo.
Mac