Wenn eine Funktionsvorlage den Rückgabetyp abgeleitet hat, gibt es eine Möglichkeit, ihn aufzurufen, ohne die Definition zu instanziieren?
Betrachten Sie einige Funktionsvorlagen wie:
template <class T>
const auto& foo() { static T t; return t; }
Die Definition wäre nicht gültig, wenn T
sie wäre void
. Trotzdem dürfen wir die Deklaration alleine instanziieren, ohne einen Fehler auszulösen:
extern template const auto& foo<void>(); // explicit instantiation declaration
Betrachten wir nun Situationen, in denen foo
aufgerufen wird, anstatt explizit instanziiert zu werden. Wenn foo
jemals in einem bewerteten Kontext aufgerufen wird, wird die Definition der Spezialisierung offensichtlich instanziiert. Was ist mit einem nicht bewerteten Kontext? Wir wissen, dass die Definition der Spezialisierung nicht instanziiert wird, wenn eine Funktionsvorlage mit einem nicht abgeleiteten Rückgabetyp in einem nicht bewerteten Kontext aufgerufen wird. Das offensichtliche Beispiel dafür ist std::declval<T>
. Es ist nicht klar, ob dies für eine Funktion mit einem abgeleiteten Rückgabetyp möglich ist.
Zum Beispiel habe ich Folgendes berücksichtigt:
static_assert(sizeof( (void)foo<void>(), char{} ) == 1);
Selbst in dieser Situation, in der der Compiler definitiv über genügend Informationen verfügt, um den sizeof
Ausdruck auszuwerten , ohne den Rückgabetyp zu kennen, tritt dennoch ein Kompilierungsfehler auf ( Godbolt-Link ).
- Welche Bestimmung des Standards erfordert die Instanziierung der Definition von
foo<void>
in dieser Situation? - Gibt es eine Möglichkeit,
foo<void>
innerhalb eines nicht bewerteten Ausdrucks aufgerufen zu werden, die seine Definition nicht instanziieren würde?
Antworten
Welche Bestimmung des Standards erfordert die Instanziierung der Definition von
foo<void>
in dieser Situation?
Obwohl nicht normativ, wird in der Anmerkung in [dcl.spec.auto] / 11 erwähnt, dass jede Verwendung einer Spezialisierung (einer Funktionsvorlage mit einem Platzhalter in ihrem deklarierten Rückgabetyp) eine implizite Instanziierung verursacht [Auszug, Hervorhebung meiner] ::
[...] [ Hinweis: Daher führt jede Verwendung einer Spezialisierung der Funktionsvorlage zu einer impliziten Instanziierung.
und darüber hinaus behandelt [dcl.spec.auto] / 14 den speziellen Fall, eine explizite Instanziierungsdeklaration zuzulassen, ohne eine Instanziierung auszulösen, während wohl auch angedeutet wird, dass die Instanziierungsmechanismen, die zum Bestimmen des Rückgabetyps für eine Funktionsvorlage ausgelöst werden, etwas von diesen getrennt sind die "regulären" Instanziierungsmechanismen [ Schwerpunkt Mine]:
Eine explizite Instanziierungsdeklaration bewirkt nicht die Instanziierung einer Entität, die unter Verwendung eines Platzhaltertyps deklariert wurde, verhindert jedoch auch nicht, dass diese Entität nach Bedarf instanziiert wird, um ihren Typ zu bestimmen . [ Beispiel:
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
- Beispiel beenden ]
wobei der Kommentar (nicht normativ) zu dem Beispiel darauf hinweist, dass eine solche im Sonderfall ausgelöste implizite Instanziierung nur für den Abzug vom Rückgabetyp verwendet wird und nicht auf die Notwendigkeit einer expliziten Instanziierungsdefinition an anderer Stelle verzichtet.
Gibt es eine Möglichkeit,
foo<void>
innerhalb eines nicht bewerteten Ausdrucks aufgerufen zu werden, die seine Definition nicht instanziieren würde?
Angesichts der obigen Diskussion würde ich sagen: Nein. Das Aufrufen selbst innerhalb eines nicht bewerteten Ausdrucks würde unter die (nicht normative) "Verwendung von" fallen.