Última atualização:2026-10-12
Templates de variável no C++17¶
Templates de variável em C++那些事¶
Ao escrever código com templates, frequentemente precisamos definir e usar várias características de tipo (type traits). Essas características geralmente são usadas para fazer verificações sobre tipos em tempo de compilação; std::is_const, std::is_same e std::is_reference, fornecidos pela STL, são exemplos desse tipo. Por meio dessas características, os desenvolvedores podem tomar decisões em tempo de compilação com base nas propriedades dos tipos.
Este artigo apresentará como usar os templates de variável do C++14 (variable templates) para simplificar a escrita de características de tipo, com um exemplo simples.
C++11¶
No C++11, escrever uma característica de tipo geralmente exige usar struct ou std::integral_constant para encapsular um valor booleano. Por exemplo, para escrever a característica de tipo is_float, que verifica se um tipo é float, podemos implementar da seguinte forma:
template <typename T>
struct is_float {
static constexpr bool value = std::is_same<T, float>::value;
};
Ou, de forma um pouco mais concisa, usando um alias de tipo e std::integral_constant:
Embora isso seja mais conciso do que usar struct diretamente, ainda estamos definindo um tipo, e não obtendo diretamente um valor booleano. Para usar essa característica, é preciso obter o valor booleano por meio do membro ::value:
template <typename T>
void test(T t){
if (is_float<T>::value){
std::cout << "I'm a float" << std::endl;
} else {
std::cout << "I'm not a float" << std::endl;
}
}
Isso funciona, mas ainda há duas deficiências:
1. É preciso acessar ::value toda vez que a característica de tipo é usada.
2. Ao definir uma nova característica de tipo, é obrigatório declarar um novo tipo ou alias de tipo, aumentando a redundância do código.
A introdução dos templates de variável no C++14¶
O C++14 introduziu os templates de variável, permitindo-nos definir diretamente variáveis que dependem de tipos. Esse recurso simplifica a escrita de características de tipo, de modo que não precisamos mais usar alias de tipo ou struct para encapsular valores booleanos: podemos definir o valor booleano diretamente.
A característica is_float reescrita fica assim:
Essa forma parece mais concisa e clara, eliminando código desnecessário. O uso também fica mais prático:
template <typename T>
void test(T t){
if (is_float<T>){
std::cout << "I'm a float" << std::endl;
} else {
std::cout << "I'm not a float" << std::endl;
}
}
Comparado à forma anterior, ao usar templates de variável, não é mais preciso acessar o valor booleano via ::value, e o código fica mais conciso e intuitivo.
Vantagens dos templates de variável¶
- Redução de código redundante: os templates de variável permitem definir diretamente variáveis baseadas em tipos, evitando o código redundante de usar
structoustd::integral_constantpara encapsular valores booleanos. - Maior legibilidade: os templates de variável, ao simplificar a sintaxe, tornam o código mais claro, especialmente ao escrever muitas características de tipo.
- Suporte a especialização de templates: diferente dos templates de alias de tipo, os templates de variável podem ser especializados, tanto de forma completa quanto parcial. Podemos definir lógica específica para determinados tipos sem nos preocupar com escalabilidade.
Melhorias adicionais no C++17¶
O C++17 expandiu ainda mais a aplicação dos templates de variável, fornecendo utilitários de template de variável para cada característica de tipo. Por exemplo, std::is_same ganhou o template de variável std::is_same_v, usado para simplificar o acesso ao valor da característica de tipo:
Dessa forma, o uso das características de tipo fica mais conciso, e os desenvolvedores podem usar diretamente o template de variável sem precisar acessar ::value a cada vez.
Caso prático¶
Esse recurso é bastante usado na prática; por exemplo: para alocar blocos de memória de tamanhos diferentes em um banco de dados, podemos inicializar tamanhos de bloco para tipos diferentes por meio de templates.
template <typename T>
constexpr size_t block_size = 1024; // 默认大小
template <>
constexpr size_t block_size<double> = 2048; // double 类型需要更多内存
Tópicos relacionados¶
- Atributo [[nodiscard]] no C++17 | C++那些事
- C++17 std::string_view | C++那些事
- Recursos de memória PMR no C++17 | C++那些事
- Dezessete funcionalidades avançadas do C++17 | C++那些事
- Dedução de argumentos de template de classe CTAD no C++17 | C++那些事
- C++17 optional_ref | C++那些事
- C++17 std::variant | C++那些事
- Vinculações estruturadas no C++17 | C++那些事
- Dedução com auto em templates no C++17 | C++那些事