💡 Resumo:A família const do C++ completa: const vs constexpr vs constinit, consteval e membros const, e como o deducing this do C++23 colapsa quatro sobrecargas const/ref em uma única função.
Última atualização:2026-10-24
A família completa do const em C++¶
Sumário
- const
- constexpr
- C++20
- consteval
- constinit
Nota: todos os exemplos de código deste artigo foram publicados no Planeta do Conhecimento.
1.const¶
const é uma das primeiras palavras-chave que conhecemos ao aprender C++/C; geralmente é usada como cv-qualifier, indicando que o objeto é imutável. Ela não garante a avaliação em tempo de compilação; o momento exato da avaliação fica a critério do compilador. Por exemplo:
O const às vezes pode ser usado em expressões constantes em tempo de compilação, mas há exceções, por exemplo:
const double count_1 = 3.3;
std::array<double, static_cast<int>(count_1)> moreDoubles1 {1.1, 2.2, 3.3};
Nesse caso, ocorre o erro: the value of 'count_1' is not usable in a constant expression
Mas assim funciona normalmente:
A essência está na avaliação de expressões em tempo de compilação; por isso, o C++11 introduziu o constexpr.
2.constexpr¶
constexpr pode ser usado para especificar que o valor de uma variável pode aparecer em uma expressão constante; basta trocar o const do exemplo anterior por constexpr para que ele funcione.
constexpr double count_2 = 3.3;
std::array<double, static_cast<int>(count_2)> moreDoubles2 {1.1, 2.2, 3.3};
constexpr não necessariamente só executa em tempo de compilação. Seu significado essencial é que pode ser calculado em tempo de compilação, mas se uma variável ou função constexpr for usada em tempo de execução, ela também pode ser executada em tempo de execução.
Por exemplo: result1 e result2 são completamente diferentes — result1 é calculado em tempo de compilação, mas result2 é calculado em tempo de execução. Fica a dúvida: você sabe por quê?
Portanto, não é porque uma função foi marcada com constexpr que ela será necessariamente calculada em tempo de compilação.
constexpr int compileTimeSum(int a, int b) {
return a + b;
}
int main() {
constexpr int result1 = compileTimeSum(3, 5);
int x = 10;
int result2 = compileTimeSum(x, 20);
return 0;
}
Então, o que pode garantir isso? Foi então que chegou o C++20.
3.C++20¶
3.1 consteval¶
O consteval resolve o problema acima: ele só pode ser usado em funções e força todas as chamadas a acontecerem em tempo de compilação. Se trocarmos agora o constexpr do exemplo acima por consteval, o que acontecerá com result2?
Ocorrerá o erro: call to consteval function 'compileTimeSum(x, 20)' is not a constant expression
consteval int compileTimeSum(int a, int b) {
return a + b;
}
int main() {
constexpr int result1 = compileTimeSum(3, 5);
int x = 10;
int result2 = compileTimeSum(x, 20);
return 0;
}
Se o consteval for usado em uma variável, também haverá erro: error: a variable cannot be declared 'consteval'.
3.2 constinit¶
O constinit pode forçar a inicialização constante de variáveis estáticas ou de armazenamento local de thread.
- Não pode ser usado junto com constexpr ou consteval
- É um especificador não relativo a tipo, cuja função é fazer um assert
- Garante que a variável seja estaticamente inicializada
- Só pode ser aplicado a static ou thread_local
Por exemplo: o código a seguir gera erro de compilação: error: 'constinit' can only be applied to a variable with static or thread storage duration
constinit int a = 100;
int main() {
++a;
constinit auto b = 100; // error
// b has thread storage duration
constinit thread_local auto b = 100;
}
C++23 deducing this: escreva as sobrecargas const/ref uma única vez¶
Quem avança na família const acaba no mesmo muro: um getter que deve se comportar bem para objetos const e não const, lvalues e rvalues, precisa de até quatro sobrecargas quase idênticas — e no dia em que alguém editar só uma, elas começam a divergir em silêncio.
O «deducing this» do C++23 (parâmetro de objeto explícito, proposta P0847) elimina a duplicação. A função membro declara o próprio objeto como parâmetro explícito; o compilador deduz o tipo junto com a constância e a categoria de valor, e um único template cobre os quatro casos:
class Widget {
int value_{42};
public:
// Before C++23 you needed up to four overloads:
// int& get() & { return value_; }
// int get() const& { return value_; }
// int&& get() && { return std::move(value_); }
// ...
// C++23 deducing this — one template covers them all:
template <typename Self>
auto&& get(this Self&& self) {
return std::forward<Self>(self).value_;
}
};
Ao chamar get() num lvalue const, Self deduz como const Widget&; num rvalue, como Widget&& e std::forward move. Decidir o que deve ser const continua sendo papel do que foi explicado antes; deducing this só remove o copia-e-cola.
O recurso também assume duas tarefas do CRTP — misturar comportamento e deduzir o tipo derivado — sem o boilerplate do template base. Suporte: GCC 14+, Clang 18+, MSVC desde o VS 2022 17.2.
Perguntas frequentes¶
Deducing this pode substituir as sobrecargas const?¶
Sim no caso comum. Um único template sobre Self&& com std::forward se comporta corretamente para &, const&, && e const&&. Sobrecargas separadas só quando o comportamento realmente difere por qualificação — o que é raro.
Quais compiladores suportam deducing this?¶
GCC 14 ou superior, Clang 18 ou superior e MSVC desde o Visual Studio 2022 17.2. É um recurso do C++23: compile com -std=c++23 (ou c++2b em drivers antigos).
Deducing this é a mesma coisa que CRTP?¶
Há sobreposição: ambos deduzem o tipo mais derivado. Deducing this dispensa o template base, funciona em lambdas (lambdas recursivas!) e mantém a hierarquia limpa; o CRTP ainda serve quando o mixin precisa ser uma classe base reutilizável.
Tópicos relacionados¶
- Funções virtuais puras e classes abstratas em C++ | C++那些事
- Asserções com assert em C++ | C++那些事
- Bit fields em C++ | C++那些事
- Implementando polimorfismo de C++ em linguagem C | C++那些事
- const em C++ explicado: constantes, ponteiro const vs ponteiro para const | C++那些事
- O operador de desreferência * em C++ | C++那些事
- Inicialização e atribuição em C++ | C++那些事
- Formas de retornar múltiplos valores em C++ | C++那些事
- A palavra-chave mutable em C++ | C++那些事
- C++ restrict e otimização do compilador | C++那些事