decltype (C++)

O especificador de tipo decltype produz o tipo de uma expressão especificada. O especificador de tipo decltype junto com a palavra-chave auto, é útil principalmente para desenvolvedores que gravam bibliotecas de modelos. Use auto e decltype declare um modelo de função cujo tipo de retorno depende dos tipos de seus argumentos de modelo. Ou, use auto e decltype declare um modelo de função que encapsula uma chamada para outra função e, em seguida, retorna o tipo de retorno da função encapsulada.

Sintaxe

decltype( expression )

Parâmetros

expression
Uma expressão. Para obter mais informações, confira Expressões.

Valor retornado

O tipo do parâmetro expression.

Comentários

Há suporte para o especificador de tipo decltype no Visual Studio 2010 e em versões posteriores, e pode ser usado com código gerenciado ou nativo. Há suporte para decltype(auto) (C++14) no Visual Studio 2015 e posterior.

O compilador usa as seguintes regras para determinar o expression tipo do parâmetro.

  • Se o expression parâmetro for um identificador ou um acesso de membro de classe, decltype(expression) será o tipo da entidade nomeada por expression. Se não houver essa entidade ou o parâmetro nomear um conjunto de funções sobrecarregadas, o expression compilador produzirá uma mensagem de erro.

  • Se o parâmetro for uma chamada para uma função ou uma função de operador sobrecarregada, decltype(expression) é o expression tipo de retorno da função. Os parênteses em torno de um operador sobrecarregado são ignorados.

  • Se o parâmetro for um rvalue, decltype(expression) será o expression tipo de expression. Se o parâmetro for um lvalue, decltype(expression) será uma referência lvalue para o expression tipo de expression.

O exemplo de código a seguir demonstra alguns usos do especificador de tipo decltype. Primeiro, suponha que você tenha codificado as instruções a seguir.

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

Em seguida, examine os tipos retornados pelas quatro instruções decltype na tabela a seguir.

Instrução Tipo Observações
decltype(fx()); const int&& Uma referência rvalue para um const int.
decltype(var); int O tipo da variável var.
decltype(a->x); double O tipo do acesso de membro.
decltype((a->x)); const double& Os parênteses internos fazem com que a instrução seja avaliada como uma expressão em vez de um acesso de membro. E, como a é declarado como um ponteiro const, o tipo é uma referência para const double.

decltype e auto

Em C++14, você pode usar decltype(auto) sem nenhum tipo de retorno à direita para declarar um modelo de função cujo tipo de retorno depende dos tipos de seus argumentos de modelo.

Em C++11, você pode usar o decltype especificador de tipo em um tipo de retorno à direita, juntamente com a auto palavra-chave, para declarar um modelo de função cujo tipo de retorno depende dos tipos de seus argumentos de modelo. Por exemplo, considere o exemplo de código a seguir no qual o tipo de retorno do modelo de função depende dos tipos dos argumentos do modelo. No exemplo de código, o espaço reservado indica que o UNKNOWN tipo de retorno não pode ser especificado.

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

A introdução do decltype especificador de tipo permite que um desenvolvedor obtenha o tipo da expressão que o modelo de função retorna. Use a sintaxe de declaração de função alternativa, mostrada posteriormente, a palavra-chave auto e o especificador de tipo decltype para declarar um tipo de retorno posterior. O tipo de retorno especificado tardiamente é determinado quando a declaração é compilada, em vez de quando é codificada.

O protótipo a seguir ilustra a sintaxe de uma declaração de função alternativa. Os const qualificadores e volatile a especificação de throwexceção são opcionais. O function_body espaço reservado representa uma instrução composta que especifica o que a função faz. Como prática recomendada de codificação, o espaço reservado expression na instrução deve corresponder à expressão especificada pela return instrução, se houver, no function_body.decltype

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

No exemplo de código a seguir, o tipo de retorno especificado tardiamente do myFunc modelo de função é determinado pelos tipos dos argumentos e tu modelo. Como melhor prática de codificação, o exemplo de código também usa referências rvalue e o modelo de função forward, que dá suporte para encaminhamento perfeito. Para obter mais informações, consulte Declarador de referência 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 e funções de encaminhamento (C++11)

As funções de encaminhamento encapsulam chamadas para outras funções. Considere um modelo de função que encaminha seus argumentos, ou os resultados de uma expressão que envolve esses argumentos, para outra função. Além disso, a função de encaminhamento retorna o resultado da chamada para a outra função. Nesse cenário, o tipo de retorno da função de encaminhamento deve ser igual ao tipo de retorno da função encapsulada.

Nesse cenário, você não pode escrever uma expressão de tipo apropriada sem o decltype especificador de tipo. O decltype especificador de tipo habilita funções de encaminhamento genéricas porque não perde as informações necessárias sobre se uma função retorna um tipo de referência. Para obter um exemplo de código de uma função de encaminhamento, consulte o exemplo de modelo de função anterior myFunc .

Exemplos

O exemplo de código a seguir declara o tipo de retorno especificado tardiamente do modelo Plus()de função . A função Plus processa seus dois operandos com a sobrecarga operator+. Assim, a interpretação do operador plus (+) e do Plus tipo de retorno da função depende dos tipos dos argumentos da função.

// 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 posterior: O compilador analisa os argumentos decltypequando os modelos são declarados em vez de instanciados. Assim, se uma especialização não dependente for encontrada no decltype argumento, ela não será adiada para o tempo de instanciação, ela é processada imediatamente e quaisquer erros resultantes são diagnosticados naquele momento.

O exemplo a seguir mostra esse erro do compilador gerado no momento da declaração:

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

Requisitos

Visual Studio 2010 ou versões posteriores.

decltype(auto) exige o Visual Studio 2015 ou posterior.