Namespaces
Variants

Placeholder type specifiers (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Ein Platzhalter-Typspezifizierer bezeichnet einen Platzhaltertyp , der später ersetzt wird, typischerweise durch Ableitung von einem Initialisierer .

Inhaltsverzeichnis

Syntax

Typ-Einschränkung  (optional) auto (1)
Typ-Einschränkung  (optional) decltype(auto) (2) (seit C++14)
type-constraint - (since C++20) ein concept Name, optional qualifiziert, optional gefolgt von einer Template-Argumentliste eingeschlossen in <>
1) Der Typ wird unter Verwendung der Regeln für Template-Argument-Deduktion abgeleitet.
2) Typ ist decltype(expr) , wobei expr der Initialisierer oder die Operanden in return-Anweisungen ist.

Der Platzhalter auto kann von Modifikatoren begleitet werden, wie const oder & , die an der Typableitung teilnehmen werden. Der Platzhalter decltype ( auto ) muss der alleinige Bestandteil des deklarierten Typs sein. (seit C++14)

Wenn type-constraint vorhanden ist, sei T der für den Platzhalter abgeleitete Typ, dann führt der type-constraint einen constraint expression wie folgt ein:

  • Wenn type-constraint Concept<A 1 , ..., A n > ist, dann ist der constraint expression Concept<T, A 1 , ..., A n > ;
  • andernfalls ( type-constraint ist Concept ohne Argumentliste), ist der constraint expression Concept<T> .

Die Ableitung schlägt fehl, wenn der constraint expression ungültig ist oder false zurückgibt.

(since C++20)

Erklärung

Ein Platzhalter-Typspezifizierer kann in den folgenden Kontexten erscheinen:

Parameterdeklarationen

In den folgenden Parameterdeklarationen kann der Typ des deklarierten Parameters von der Syntax (1) sein:

  • Wenn ein Parameter eines Lambda-Ausdrucks einen Platzhaltertyp hat, ist der Lambda-Ausdruck ein generischer Lambda.
(since C++14)
(since C++17)
(since C++20)

Funktionsdeklarationen

Ein Platzhaltertyp kann in den Deklarationsspezifizierern für einen Funktionsdeklarator erscheinen, der einen nachgestellten Rückgabetyp enthält.

Ein Platzhaltertyp kann in den Deklarationsspezifizierern oder Typspezifizierern im deklarierten Rückgabetyp eines Funktionsdeklarators erscheinen. Rückgabetypableitung wird in diesem Fall angewendet.

(seit C++14)
auto f() -> int; // OK: f gibt int zurück
auto g() { return 0.0; } // OK seit C++14: g gibt double zurück
auto h(); // OK seit C++14: h's Rückgabetyp wird bei Definition abgeleitet

Variablendeklarationen

Der Typ einer Variable, die mit einem Platzhaltertyp deklariert wird, wird von ihrem Initialisierer abgeleitet. Diese Verwendung ist in einer initialisierenden Deklaration einer Variable zulässig.

Der Platzhaltertyp kann nur als einer der Deklarationsspezifizierer in der Deklarationsspezifizierer-Sequenz oder als einer der Typspezifizierer in einem nachgestellten Rückgabetyp auftreten, der den Typ angibt, der einen solchen Deklarationsspezifizierer ersetzt. In diesem Fall muss die Deklaration mindestens eine Variable deklarieren, und jede Variable muss einen nicht-leeren Initialisierer haben.

// "auto"s in Deklarationsspezifizierern
auto x = 5; // OK: x hat Typ int
const auto *v = &x, u = 6; // OK: v hat Typ const int*, u hat Typ const int
static auto y = 0.0; // OK: y hat Typ double
auto f() -> int;
auto (*fp)() -> auto = f; // OK: das "auto" im Trailing-Return-Type
                          // kann von f abgeleitet werden

Strukturierte Bindungsdeklarationen

Der auto -Spezifizierer kann in einer strukturierten Bindungsdeklaration verwendet werden.

(seit C++17)

new Ausdrücke

Ein Platzhaltertyp kann in der Typspezifizierer-Sequenz der Typ-ID eines new-Ausdrucks verwendet werden. In einer solchen Typ-ID muss der Platzhaltertyp als einer der Typspezifizierer in der Typspezifizierer-Sequenz oder als nachgestellter Rückgabetyp erscheinen, der den Typ angibt, der einen solchen Typspezifizierer ersetzt.

Funktionsstil-Cast

Der auto -Typspezifizierer kann als Typspezifizierer eines Funktionsstil-Casts verwendet werden.

(seit C++23)

Hinweise

Bis C++11 hatte auto die Semantik eines storage duration specifier .

Ein Programm, das einen Platzhaltertyp in einem Kontext verwendet, der nicht explizit oben angegeben ist, ist fehlerhaft.

Falls eine Deklaration mehrere Entitäten deklariert und die Deklarationsspezifizierer-Sequenz einen Platzhaltertyp verwendet, ist das Programm fehlerhaft, wenn eine der folgenden Bedingungen erfüllt ist:

  • Einige der deklarierten Entitäten sind keine Variablen.
  • Der Typ, der den Platzhaltertyp ersetzt, ist nicht in jeder Deduktion derselbe.
auto f() -> int, i = 0; // Fehler: Deklariert eine Funktion und eine Variable mit "auto"
auto a = 5, b = {1, 2}; // Fehler: Unterschiedliche Typen für "auto"

Wenn eine Funktion oder Variable mit einem nicht ersetzten Platzhaltertyp durch einen Ausdruck referenziert wird, ist das Programm fehlerhaft.

auto v = 1;
auto l = [&]
{
    v++;
    return l;// Fehler: Der Platzhaltertyp für l wurde nicht ersetzt
};
std::function<void()> p = [&]
{
    v++;
    return p;// OK
};

Das auto Schlüsselwort kann auch in einem geschachtelten Namensspezifizierer verwendet werden. Ein geschachtelter Namensspezifizierer der Form auto :: ist ein Platzhalter, der durch einen Klassen- oder Aufzählungstyp ersetzt wird, gemäß den Regeln für die constrained type Platzhalterableitung.

(concepts TS)
Feature-Test-Makro Wert Std Feature
__cpp_decltype_auto 201304L (C++14) decltype ( auto )

Schlüsselwörter

auto , decltype

Beispiel

#include <iostream>
#include <utility>
template<class T, class U>
auto add(T t, U u) { return t + u; } // der Rückgabetyp ist der Typ von operator+(T, U)
// perfektes Weiterleiten eines Funktionsaufrufs muss decltype(auto) verwenden
// falls die aufgerufene Funktion eine Referenz zurückgibt
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}
template<auto n> // C++17 auto Parameterdeklaration
auto f() -> std::pair<decltype(n), decltype(n)> // auto kann nicht aus Initialisierungsliste ableiten
{
    return {n, n};
}
int main()
{
    auto a = 1 + 2;          // Typ von a ist int
    auto b = add(1, 1.2);    // Typ von b ist double
    static_assert(std::is_same_v<decltype(a), int>);
    static_assert(std::is_same_v<decltype(b), double>);
    auto c0 = a;             // Typ von c0 ist int, enthält eine Kopie von a
    decltype(auto) c1 = a;   // Typ von c1 ist int, enthält eine Kopie von a
    decltype(auto) c2 = (a); // Typ von c2 ist int&, ein Alias von a
    std::cout << "before modification through c2, a = " << a << '\n';
    ++c2;
    std::cout << " after modification through c2, a = " << a << '\n';
    auto [v, w] = f<0>(); // strukturierte Bindungsdeklaration
    auto d = {1, 2}; // OK: Typ von d ist std::initializer_list<int>
    auto n = {5};    // OK: Typ von n ist std::initializer_list<int>
//  auto e{1, 2};    // Fehler seit DR n3922, davor std::initializer_list<int>
    auto m{5};       // OK: Typ von m ist int seit DR n3922, davor initializer_list<int>
//  decltype(auto) z = { 1, 2 } // Fehler: {1, 2} ist kein Ausdruck
    // auto wird häufig für unbenannte Typen wie Lambda-Ausdrücke verwendet
    auto lambda = [](int x) { return x + 3; };
//  auto int x; // gültig in C++98, Fehler ab C++11
//  auto x;     // gültig in C, Fehler in C++
    [](...){}(c0, c1, v, w, d, n, m, lambda); // unterdrückt "unused variable" Warnungen
}

Mögliche Ausgabe:

before modification through c2, a = 3
 after modification through c2, a = 4

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 1265 C++11 der auto Spezifizierer konnte verwendet werden, um eine Funktion mit einem nachgestellten
Rückgabetyp und eine Variable in einer Deklarationsanweisung zu deklarieren
verboten
CWG 1346 C++11 eine geklammerte Ausdrucksliste konnte nicht einer auto Variable zugewiesen werden erlaubt
CWG 1347 C++11 eine Deklaration mit dem auto Spezifizierer konnte zwei Variablen
mit den Typen T und std:: initializer_list < T > definieren
verboten
CWG 1852 C++14 der auto Spezifizierer in decltype ( auto ) war ebenfalls ein Platzhalter kein Platzhalter
in diesem Fall
CWG 1892 C++11 der Rückgabetyp eines Funktionszeiger-Typ-IDs konnte auto sein verboten
CWG 2476 C++11 die Lösung von CWG Issue 1892 verbot die Ableitung
des Rückgabetyps von Funktionszeiger-Variablen aus Initialisierern
erlaubt
N3922 C++11 Direkt-List-Initialisierung von auto leitet std::initializer_list ab ungültig für mehr als ein
Element, leitet Elementtyp
für einzelnes Element ab

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 9.2.9.6 Platzhalter-Typspezifizierer [dcl.spec.auto]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 9.2.8.5 Platzhalter-Typspezifizierer [dcl.spec.auto]
  • C++17-Standard (ISO/IEC 14882:2017):
  • 10.1.7.4 Der auto -Spezifizierer [dcl.spec.auto]
  • C++14-Standard (ISO/IEC 14882:2014):
  • 7.1.6.4 auto Spezifizierer [dcl.spec.auto]
  • C++11-Standard (ISO/IEC 14882:2011):
  • 7.1.6.4 auto Spezifizierer [dcl.spec.auto]