decltype (C++)

Der decltype Typbezeichner liefert den Typ eines angegebenen Ausdrucks. Der decltype Typbezeichner ist zusammen mit dem auto Schlüsselwort (keyword) in erster Linie für Entwickler nützlich, die Vorlagenbibliotheken schreiben. Verwenden und decltype deklarieren Sie auto eine Funktionsvorlage, deren Rückgabetyp von den Typen ihrer Vorlagenargumente abhängt. Sie können auch eine Funktionsvorlage verwenden auto und decltype deklarieren, die einen Aufruf einer anderen Funktion umschließt, und gibt dann den Rückgabetyp der umschlossenen Funktion zurück.

Syntax

decltype( expression )

Parameter

expression
Ein Ausdruck. Weitere Informationen finden Sie unter Ausdrücke.

Rückgabewert

Der Typ des expression-Parameters.

Hinweise

Der decltype Typbezeichner wird in Visual Studio 2010 oder höheren Versionen unterstützt und kann mit systemeigenem oder verwaltetem Code verwendet werden. decltype(auto) (C++14) wird in Visual Studio 2015 und höher unterstützt.

Der Compiler verwendet die folgenden Regeln, um den Typ des expression Parameters zu bestimmen.

  • Wenn es sich bei dem expression Parameter um einen Bezeichner oder einen Klassenmemembezugriff handelt, decltype(expression) handelt es sich um den Typ der Entität, die von expression. Wenn keine solche Entität vorhanden ist oder der expression Parameter eine Reihe überladener Funktionen benennt, liefert der Compiler eine Fehlermeldung.

  • Wenn der expression Parameter ein Aufruf einer Funktion oder einer überladenen Operatorfunktion ist, decltype(expression) ist der Rückgabetyp der Funktion. Klammern um einen überladenen Operator werden ignoriert.

  • Wenn der expression Parameter ein Wert ist, decltype(expression) ist der Typ von expression. Wenn der expression Parameter ein lvalue ist, decltype(expression) ist ein lvalue-Verweis auf den Typ von expression.

Im folgenden Codebeispiel wird die Verwendung des decltype Typbezeichners veranschaulicht. Gehen Sie zunächst davon aus, dass Sie die folgenden Anweisungen codiert haben.

int var;
const int&& fx();
struct A { double x; };
const A* a = new A();

Überprüfen Sie als Nächstes die Typen, die von den vier decltype Anweisungen in der folgenden Tabelle zurückgegeben werden.

Anweisung Typ Notizen
decltype(fx()); const int&& Ein Rvalue-Verweis auf ein const int.
decltype(var); int Der Typ der var-Variablen.
decltype(a->x); double Der Typ des Memberzugriffs.
decltype((a->x)); const double& Die innere Klammer bewirkt, dass die Anweisung als Ausdruck anstatt als Memberzugriff ausgewertet wird. Und da a als const Zeiger deklariert wird, ist der Typ ein Verweis auf const double.

decltype und auto

In C++14 können decltype(auto) Sie ohne nachgestellten Rückgabetyp eine Funktionsvorlage deklarieren, deren Rückgabetyp von den Typen ihrer Vorlagenargumente abhängt.

In C++11 können Sie den decltype Typbezeichner für einen nachfolgenden Rückgabetyp zusammen mit dem auto Schlüsselwort (keyword) verwenden, um eine Funktionsvorlage zu deklarieren, deren Rückgabetyp von den Typen seiner Vorlagenargumente abhängt. Betrachten Sie beispielsweise das folgende Codebeispiel, in dem der Rückgabetyp der Funktionsvorlage von den Typen der Vorlagenargumente abhängt. Im Codebeispiel gibt der UNKNOWN Platzhalter an, dass der Rückgabetyp nicht angegeben werden kann.

template<typename T, typename U>
UNKNOWN func(T&& t, U&& u){ return t + u; };

Die Einführung des decltype Typbezeichners ermöglicht es einem Entwickler, den Typ des Ausdrucks abzurufen, den die Funktionsvorlage zurückgibt. Verwenden Sie die alternative Funktionsdeklarationssyntax, die später angezeigt wird, die auto Schlüsselwort (keyword) und den decltype Typbezeichner, um einen spät angegebenen Rückgabetyp zu deklarieren. Der spät angegebene Rückgabetyp wird bestimmt, wenn die Deklaration kompiliert wird und nicht, wenn sie codiert ist.

Der folgende Prototyp veranschaulicht die Syntax einer alternativen Funktionsdeklaration. Die const Qualifizierer und volatile die throwAusnahmespezifikation sind optional. Der function_body Platzhalter stellt eine zusammengesetzte Anweisung dar, die angibt, was die Funktion bewirkt. Als bewährte Codierungspraxis sollte der expression Platzhalter in der decltype Anweisung mit dem ausdruck übereinstimmen, der durch die return Anweisung (falls vorhanden) in der function_body.

autofunction_name(parametersopt)constopt opt->)expressiondecltype(noexceptvolatile{function_body};

Im folgenden Codebeispiel wird der spät angegebene Rückgabetyp der myFunc Funktionsvorlage durch die Typen der t Argumente und u Vorlagen bestimmt. Als bewährte Codierungspraxis verwendet das Codebeispiel auch Rvalue-Verweise und die forward Funktionsvorlage, die die perfekte Weiterleitung unterstützen. Weitere Informationen finden Sie unter Rvalue Reference Declarator: &&&.

//C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u))
        { return forward<T>(t) + forward<U>(u); };

//C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u)
        { return forward<T>(t) + forward<U>(u); };

decltype und Weiterleitungsfunktionen (C++11)

Weiterleitungsfunktionen umschließen Aufrufe von anderen Funktionen. Denken Sie an eine Funktionsvorlage, die ihre Argumente oder die Ergebnisse eines Ausdrucks, der diese Argumente beinhaltet, an eine andere Funktion weiterleitet. Darüber hinaus gibt die Weiterleitungsfunktion das Ergebnis des Aufrufs der anderen Funktion zurück. In diesem Szenario muss der Rückgabetyp der Weiterleitungsfunktion mit dem Rückgabetyp der umschlossenen Funktion identisch sein.

In diesem Szenario können Sie keinen geeigneten Typausdruck ohne den decltype Typbezeichner schreiben. Der decltype Typbezeichner ermöglicht generische Weiterleitungsfunktionen, da keine erforderlichen Informationen darüber verloren gehen, ob eine Funktion einen Verweistyp zurückgibt. Ein Codebeispiel für eine Weiterleitungsfunktion finden Sie im beispiel der vorherigen myFunc Funktionsvorlage.

Beispiele

Im folgenden Codebeispiel wird der spät angegebene Rückgabetyp der Funktionsvorlage Plus()deklariert. Die Plus Funktion verarbeitet ihre beiden Operanden mit der operator+ Überladung. Die Interpretation des Plusoperators (+) und der Rückgabetyp der Plus Funktion hängt also von den Typen der Funktionsargumente ab.

// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp

#include <iostream>
#include <string>
#include <utility>
#include <iomanip>

using namespace std;

template<typename T1, typename T2>
auto Plus(T1&& t1, T2&& t2) ->
   decltype(forward<T1>(t1) + forward<T2>(t2))
{
   return forward<T1>(t1) + forward<T2>(t2);
}

class X
{
   friend X operator+(const X& x1, const X& x2)
   {
      return X(x1.m_data + x2.m_data);
   }

public:
   X(int data) : m_data(data) {}
   int Dump() const { return m_data;}
private:
   int m_data;
};

int main()
{
   // Integer
   int i = 4;
   cout <<
      "Plus(i, 9) = " <<
      Plus(i, 9) << endl;

   // Floating point
   float dx = 4.0;
   float dy = 9.5;
   cout <<
      setprecision(3) <<
      "Plus(dx, dy) = " <<
      Plus(dx, dy) << endl;

   // String
   string hello = "Hello, ";
   string world = "world!";
   cout << Plus(hello, world) << endl;

   // Custom type
   X x1(20);
   X x2(22);
   X x3 = Plus(x1, x2);
   cout <<
      "x3.Dump() = " <<
      x3.Dump() << endl;
}
Plus(i, 9) = 13
Plus(dx, dy) = 13.5
Hello, world!
x3.Dump() = 42

Visual Studio 2017 und höher: Der Compiler analysiert decltype Argumente, wenn die Vorlagen deklariert und nicht instanziiert werden. Wenn also eine nicht abhängige Spezialisierung im decltype Argument gefunden wird, wird sie nicht auf Instanziierungszeit zurückgestellt. Sie wird sofort verarbeitet, und alle resultierenden Fehler werden zu diesem Zeitpunkt diagnostiziert.

Das folgende Beispiel zeigt einen solchen Compilerfehler, der zum Zeitpunkt der Deklaration ausgelöst wird:

#include <utility>
template <class T, class ReturnT, class... ArgsT> class IsCallable
{
public:
   struct BadType {};
   template <class U>
   static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int); //C2064. Should be declval<U>
   template <class U>
   static BadType Test(...);
   static constexpr bool value = std::is_convertible<decltype(Test<T>(0)), ReturnT>::value;
};

constexpr bool test1 = IsCallable<int(), int>::value;
static_assert(test1, "PASS1");
constexpr bool test2 = !IsCallable<int*, int>::value;
static_assert(test2, "PASS2");

Anforderungen

Visual Studio 2010 oder höher.

decltype(auto) erfordert Visual Studio 2015 oder höher.