Jeśli szablon funkcji ma wywnioskować zwracany typ, czy istnieje sposób na wywołanie go bez tworzenia wystąpienia definicji?
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 T
był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 foo
jest wywoływana, a nie jawna instancja. Oczywiście, jeśli foo
zostanie 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ć sizeof
wyraż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
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”.