Jeśli szablon funkcji ma wywnioskować zwracany typ, czy istnieje sposób na wywołanie go bez tworzenia wystąpienia definicji?

Nov 20 2020

Rozważmy szablon funkcji, taki jak:

template <class T>
const auto& foo() { static T t; return t; }

Definicja nie byłaby ważna, gdyby tak Tbyło void. Niemniej jednak możemy utworzyć wystąpienie samej deklaracji bez wywoływania błędu:

extern template const auto& foo<void>();  // explicit instantiation declaration

Rozważmy teraz sytuacje, w których foojest wywoływana, a nie jawna instancja. Oczywiście, jeśli foozostanie kiedykolwiek wywołana w ocenianym kontekście, zostanie utworzona instancja definicji specjalizacji. A co w nieocenionym kontekście? Wiemy, że jeśli szablon funkcji z niededukowanym zwracanym typem jest wywoływany w niedocenianym kontekście, definicja specjalizacji nie jest tworzona. Oczywistym tego przykładem jest std::declval<T>. Nie jest jasne, czy to samo jest możliwe w przypadku funkcji, która ma wydedukowany typ zwrotu.

Na przykład rozważałem to:

static_assert(sizeof( (void)foo<void>(), char{} ) == 1);

Jednak nawet w tej sytuacji, gdy kompilator na pewno ma wystarczająco dużo informacji, aby ocenić sizeofwyrażenie bez znajomości zwracanego typu, nadal występuje błąd kompilacji ( łącze godbolt ).

  • Jakie postanowienie Standardu wymaga konkretyzacji definicji foo<void>w tej sytuacji?
  • Czy jest jakiś sposób, który foo<void>można wywołać wewnątrz nieocenionego wyrażenia, które nie utworzyłoby jego definicji?

Odpowiedzi

3 dfrib Nov 19 2020 at 23:52

Jakie postanowienie Standardu wymaga konkretyzacji definicji foo<void>w tej sytuacji?

Chociaż nienormatywne, uwaga w [dcl.spec.auto] / 11 wspomina, że jakiekolwiek użycie specjalizacji (szablonu funkcji z symbolem zastępczym w zadeklarowanym typie zwracania) spowoduje niejawne wystąpienie [wyciąg, podkreślenie moje] :

[…] [  Uwaga: Dlatego każde użycie specjalizacji szablonu funkcji spowoduje niejawną instancję.

a ponadto, [dcl.spec.auto] / 14 obejmuje szczególny przypadek zezwalania na jawną deklarację instancji bez wyzwalania instancji, jednocześnie prawdopodobnie wskazując, że mechanizmy instancji wyzwalane w celu określenia typu zwracanego szablonu funkcji są nieco oddzielone od „regularne” mechanizmy instancji [ wyróżnienie moje]:

Jawna deklaracja instancji nie powoduje utworzenia instancji jednostki zadeklarowanej przy użyciu typu symbolu zastępczego, ale nie zapobiega również utworzeniu instancji tej jednostki w razie potrzeby w celu określenia jej typu . [  Przykład:

template <typename T> auto f(T t) { return t; }
extern template auto f(int);    // does not instantiate f<int>
int (*p)(int) = f;              // instantiates f<int> to determine its return type, but an explicit
                                // instantiation definition is still required somewhere in the program

 -  przykład końca  ]

gdzie komentarz (nienormatywny) do przykładu wskazuje, że taka niejawna instancja wyzwalana przez specjalny przypadek jest używana tylko do dedukcji typu zwracanego i nie zwalnia z potrzeby jawnej definicji instancji w innym miejscu.


Czy jest jakiś sposób, który foo<void>można wywołać wewnątrz nieocenionego wyrażenia, które nie utworzyłoby jego definicji?

Biorąc pod uwagę powyższą dyskusję, powiedziałbym: nie. Wywołanie nawet w niedocenianym wyrażeniu mieści się w (nienormatywnym) „każdym użyciu”.