Condividi tramite


decltype (C++)

L'identificatore decltype di tipo restituisce il tipo di un'espressione specificata. L'identificatore decltype di tipo, insieme alla auto parola chiave , è utile principalmente per gli sviluppatori che scrivono librerie di modelli. Usare auto e decltype per dichiarare un modello di funzione il cui tipo restituito dipende dai tipi degli argomenti del modello. In alternativa, usare auto e decltype per dichiarare un modello di funzione che esegue il wrapping di una chiamata a un'altra funzione e quindi restituisce il tipo restituito della funzione di cui è stato eseguito il wrapping.

Sintassi

decltype( expression )

Parametri

expression
Espressione. Per altre informazioni, vedere Espressioni.

Valore restituito

Tipo del parametro expression.

Osservazioni:

L'identificatore decltype di tipo è supportato in Visual Studio 2010 o versioni successive e può essere usato con codice nativo o gestito. decltype(auto) (C++14) è supportato in Visual Studio 2015 e versioni successive.

Il compilatore usa le regole seguenti per determinare il tipo del expression parametro .

  • Se il expression parametro è un identificatore o un accesso membro di classe, decltype(expression) è il tipo dell'entità denominata da expression. Se non esiste un'entità di questo tipo o il expression nome di un set di funzioni di overload, il compilatore restituisce un messaggio di errore.

  • Se il expression parametro è una chiamata a una funzione o a una funzione operatore di overload, decltype(expression) è il tipo restituito della funzione. Le parentesi di un operatore di overload vengono ignorate.

  • Se il expression parametro è un rvalue, decltype(expression) è il tipo di expression. Se il expression parametro è un lvalue, decltype(expression) è un riferimento lvalue al tipo di expression.

Nell'esempio di codice seguente vengono illustrati alcuni usi dell'identificatore decltype di tipo . In primo luogo, si supponga di aver codificato le istruzioni seguenti.

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

Esaminare quindi i tipi restituiti dalle quattro decltype istruzioni nella tabella seguente.

Istruzione Type Note
decltype(fx()); const int&& Riferimento rvalue a un oggetto const int.
decltype(var); int Il tipo di variabile var:
decltype(a->x); double Il tipo di accesso ai membri.
decltype((a->x)); const double& Le parentesi interne determinano la valutazione dell'istruzione come un'espressione anziché come un accesso ai membri. a Poiché è dichiarato come const puntatore, il tipo è un riferimento a const double.

decltype e auto

In C++14 è possibile usare decltype(auto) senza tipo restituito finale per dichiarare un modello di funzione il cui tipo restituito dipende dai tipi degli argomenti del modello.

In C++11 è possibile usare l'identificatore decltype di tipo in un tipo restituito finale, insieme auto alla parola chiave , per dichiarare un modello di funzione il cui tipo restituito dipende dai tipi degli argomenti del modello. Si consideri ad esempio l'esempio di codice seguente in cui il tipo restituito del modello di funzione dipende dai tipi degli argomenti del modello. Nell'esempio di codice il UNKNOWN segnaposto indica che non è possibile specificare il tipo restituito.

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

L'introduzione dell'identificatore decltype di tipo consente a uno sviluppatore di ottenere il tipo dell'espressione restituita dal modello di funzione. Usare la sintassi di dichiarazione di funzione alternativa visualizzata in un secondo momento, la auto parola chiave e l'identificatore decltype di tipo per dichiarare un tipo restituito specificato in ritardo. Il tipo restituito specificato in ritardo viene determinato quando la dichiarazione viene compilata, anziché quando viene codificata.

Il prototipo indicato di seguito mostra la sintassi per la dichiarazione di una funzione alternativa. I const qualificatori e volatile e la specifica dell'eccezione throw sono facoltativi. Il function_body segnaposto rappresenta un'istruzione composta che specifica le operazioni eseguite dalla funzione. Come procedura consigliata per la codifica, il expression segnaposto nell'istruzione decltype deve corrispondere all'espressione specificata dall'istruzione return , se presente, in function_body.

autofunction_name ( parametersvolatile opt) constopt opt -> decltype( expression ) noexcept { function_body };

Nell'esempio di codice seguente il tipo restituito specificato in ritardo del myFunc modello di funzione è determinato dai tipi degli argomenti del t modello e u . Come procedura consigliata per la codifica, l'esempio di codice usa anche riferimenti rvalue e il forward modello di funzione, che supportano l'inoltro perfetto. Per altre informazioni, vedere Dichiaratore di riferimento Rvalue: &&.

//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 funzioni di inoltro e (C++11)

Le funzioni di inoltro eseguono il wrapping delle chiamate ad altre funzioni. Si pensi a un modello di funzione che inoltra i relativi argomenti o i risultati di un'espressione che include tali argomenti, a un'altra funzione. Inoltre, la funzione di inoltro restituisce il risultato della chiamata all'altra funzione. In questo scenario il tipo restituito della funzione di inoltro deve essere uguale al tipo restituito della funzione di cui è stato eseguito il wrapping.

In questo scenario non è possibile scrivere un'espressione di tipo appropriata senza l'identificatore di decltype tipo. L'identificatore decltype di tipo abilita funzioni di inoltro generico perché non perde le informazioni necessarie sull'eventuale restituzione di un tipo riferimento da parte di una funzione. Per un esempio di codice di una funzione di inoltro, vedere l'esempio di modello di funzione precedente myFunc .

Esempi

Nell'esempio di codice seguente viene dichiarato il tipo restituito specificato in ritardo del modello Plus()di funzione . La Plus funzione elabora i due operandi con l'overload operator+ . L'interpretazione dell'operatore più (+) e il tipo restituito della Plus funzione dipendono quindi dai tipi degli argomenti della funzione.

// 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 e versioni successive: il compilatore analizza gli decltype argomenti quando i modelli vengono dichiarati anziché creare istanze. Pertanto, se nell'argomento decltype viene trovata una specializzazione non dipendente, non verrà posticipata al tempo di creazione di istanze, viene elaborata immediatamente e gli eventuali errori risultanti vengono diagnosticati in quel momento.

Nell'esempio seguente viene illustrato questo tipo di errore del compilatore che viene generato al momento della dichiarazione:

#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");

Requisiti

Visual Studio 2010 o versioni successive.

decltype(auto) richiede Visual Studio 2015 o versione successiva.