Ir para o conteúdo

Última atualização:2026-10-12

Dedução de tipos com decltype em C++

Sobre o autor:

Conta oficial do WeChat:

wechat

1.Uso básico

A sintaxe de decltype é:

decltype (expression)

Os parênteses aqui são indispensáveis; a função de decltype é "consultar o tipo de uma expressão". Assim, o efeito da instrução acima é retornar o tipo da expressão expression. Note que decltype apenas "consulta" o tipo da expressão, sem "avaliar" a expressão.

1.1 Deduzir o tipo de uma expressão

int i = 4;
decltype(i) a; //推导结果为int。a的类型为int。

1.2 Usar em conjunto com using/typedef para definir tipos.

using size_t = decltype(sizeof(0));//sizeof(a)的返回值为size_t类型
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);
vector<int >vec;
typedef decltype(vec.begin()) vectype;
for (vectype i = vec.begin; i != vec.end(); i++)
{
//...
}

Assim como o auto, isso também melhora a legibilidade do código.

1.3 Reutilizar tipos anônimos

Em C++, às vezes nos deparamos com alguns tipos anônimos, como:

struct 
{
    int d ;
    double b;
}anon_s;

Com a ajuda do decltype, podemos reutilizar essa estrutura anônima:

decltype(anon_s) as ;//定义了一个上面匿名的结构体

1.4 Na programação genérica, combinar com auto para rastrear o tipo de retorno de uma função

Este é também o maior uso do decltype.

template <typename T>
auto multiply(T x, T y)->decltype(x*y)
{
    return x*y;
}

O código completo está em: decltype.cpp

2.Regras de dedução

Para decltype(e), o resultado da dedução é influenciado pelas seguintes condições:

Se e for uma expressão identificador sem parênteses ou uma expressão de acesso a membro de classe, então decltype(e) é o tipo da entidade nomeada por e. Além disso, se e for uma função sobrecarregada, ocorrerá um erro de compilação. Caso contrário, supondo que o tipo de e seja T, se e for um xvalue (valor em extinção), decltype(e) será T&&. Caso contrário, supondo que o tipo de e seja T, se e for um lvalue, decltype(e) será T&. Caso contrário, supondo que o tipo de e seja T, decltype(e) será T.

Identificador refere-se aos nomes definidos pelo próprio programador, excluindo as palavras-chave, literais e demais marcas que o compilador precisa usar; a expressão correspondente a um único identificador é uma expressão identificador. Por exemplo:

int arr[4]
então arr é uma expressão identificador, mas arr[3]+0 não é.

Veja os exemplos a seguir:

int i = 4;
int arr[5] = { 0 };
int *ptr = arr;
struct S{ double d; }s ;
void Overloaded(int);
void Overloaded(char);//重载的函数
int && RvalRef();
const bool Func(int);

//规则一:推导为其类型
decltype (arr) var1; //int[] 标记符表达式

decltype (ptr) var2;//int *  标记符表达式

decltype(s.d) var3;//doubel 成员访问表达式

//decltype(Overloaded) var4;//重载函数。编译错误。

//规则二:将亡值。推导为类型的右值引用。

decltype (RvalRef()) var5 = 1;

//规则三:左值,推导为类型的引用。

decltype ((i))var6 = i;     //int&

decltype (true ? i : i) var7 = i; //int&  条件表达式返回左值。

decltype (++i) var8 = i; //int&  ++i返回i的左值。

decltype(arr[5]) var9 = i;//int&. []操作返回左值

decltype(*ptr)var10 = i;//int& *操作返回左值

decltype("hello")var11 = "hello"; //const char(&)[9]  字符串字面常量为左值,且为const左值。


//规则四:以上都不是,则推导为本类型

decltype(1) var12;//const int

decltype(Func(1)) var13=true;//const bool

decltype(i++) var14 = i;//int i++返回右值

Referência de estudo: https://www.cnblogs.com/QG-whz/p/4952980.html

Tópicos relacionados

Comentários