SFINAE
Habilite funções condicionalmente
SFINAE é uma aula grátis de C++ Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C++ Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C++ Academy inclui 4 aulas no total.
O que significa SFINAE?
SFINAE significa "Falha de Substituição Não é um Erro". Quando o compilador substitui os argumentos do modelo e o resultado é malformado, esse candidato é simplesmente removido, em vez de causar um erro grave.
- Ela permite sobrecargas condicionais.
- É a base da seleção em tempo de compilação.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
isOdd(T n) { return n % 2 != 0; }
int main() {
std::cout << std::boolalpha << isOdd(3) << '\n';
return 0;
}Falha de Substituição na Prática
Se substituir um tipo tornar inválida a assinatura de uma função, o compilador a ignora silenciosamente e continua procurando outros candidatos.
#include <iostream>
template <typename T>
auto sizeOfValue(T t) -> decltype(t.size()) { return t.size(); }
int main() {
std::string s = "hello";
std::cout << sizeOfValue(s) << '\n';
return 0;
}Duas Sobrecargas, Uma Vence
Forneça duas sobrecargas nas quais exatamente uma seja substituída com sucesso para um determinado tipo. SFINAE descarta a inválida.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, const char*>::type
name() { return "integral"; }
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, const char*>::type
name() { return "floating"; }
int main() {
std::cout << name<int>() << ' ' << name<double>() << '\n';
return 0;
}decltype e SFINAE de Expressão
Usar decltype em uma expressão do tipo de retorno faz com que uma função exista apenas se essa expressão for válida para o tipo.
#include <iostream>
template <typename T>
auto tryDouble(T x) -> decltype(x + x) { return x + x; }
int main() {
std::cout << tryDouble(21) << '\n';
std::cout << tryDouble(2.5) << '\n';
return 0;
}Detectando um Membro
Um truque clássico de SFINAE detecta se um tipo tem determinado membro verificando se uma expressão que o utiliza pode ser compilada.
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T>
auto hasSize(int) -> decltype(std::declval<T>().size(), std::true_type{});
template <typename T>
std::false_type hasSize(...);
int main() {
std::cout << std::boolalpha;
std::cout << decltype(hasSize<std::vector<int>>(0))::value << '\n';
std::cout << decltype(hasSize<int>(0))::value << '\n';
return 0;
}A Alternativa de Reserva ...
Uma sobrecarga que recebe ... (argumentos variáveis) tem a menor prioridade. Ela funciona como opção abrangente quando a sobrecarga restringida por SFINAE falha.
#include <iostream>
template <typename T>
auto pick(int) -> decltype(T{}.value, void()) { std::cout << "has value\n"; }
template <typename T>
void pick(...) { std::cout << "no value\n"; }
struct WithValue { int value = 0; };
int main() {
pick<WithValue>(0);
pick<int>(0);
return 0;
}void_t
No C++17, std::void_t simplifica a detecção: ele mapeia quaisquer tipos bem formados para void, de modo que uma especialização seja ativada apenas quando a expressão verificada for válida.
#include <iostream>
#include <type_traits>
#include <vector>
template <typename T, typename = void>
struct HasSize : std::false_type {};
template <typename T>
struct HasSize<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};
int main() {
std::cout << std::boolalpha;
std::cout << HasSize<std::vector<int>>::value << '\n';
std::cout << HasSize<int>::value << '\n';
return 0;
}Por que não Apenas um Erro?
Sem SFINAE, uma substituição inválida seria um erro grave de compilação, do qual não seria possível se recuperar. SFINAE a transforma silenciosamente em "não é um candidato".
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, bool>::type
isNull(T p) { return p == nullptr; }
int main() {
int x = 0;
std::cout << std::boolalpha << isNull(&x) << '\n';
return 0;
}Alternativa com Despacho por Marcadores
SFINAE pode ser difícil de ler. O despacho por marcadores escolhe uma implementação usando pequenos tipos marcadores e a resolução de sobrecarga.
#include <iostream>
#include <type_traits>
template <typename T>
void impl(T v, std::true_type) { std::cout << "integral: " << v << '\n'; }
template <typename T>
void impl(T v, std::false_type) { std::cout << "other: " << v << '\n'; }
template <typename T>
void handle(T v) { impl(v, std::is_integral<T>{}); }
int main() {
handle(5);
handle(2.5);
return 0;
}SFINAE e if constexpr
No C++17, if constexpr frequentemente substitui SFINAE para ramificações dentro de uma única função, pois os ramos não utilizados são descartados em tempo de compilação.
#include <iostream>
#include <type_traits>
template <typename T>
void describe(T v) {
if constexpr (std::is_integral<T>::value) {
std::cout << "integral: " << v << '\n';
} else {
std::cout << "other: " << v << '\n';
}
}
int main() {
describe(7);
describe(3.14);
return 0;
}Juntando Tudo
SFINAE é especialmente útil quando você precisa selecionar entre modelos de função separados com base nas propriedades do tipo, no nível da sobrecarga.
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_signed<T>::value, T>::type
absValue(T v) { return v < 0 ? -v : v; }
int main() {
std::cout << absValue(-9) << '\n';
return 0;
}Verificação Rápida
Teste sua compreensão de SFINAE.
Recapitulação
Você aprendeu sobre SFINAE:
- uma substituição inválida remove um candidato em vez de gerar um erro
- é usada com
enable_if,decltypeevoid_tpara habilitar funções condicionalmente - uma sobrecarga com
...funciona como alternativa de reserva - as alternativas modernas incluem despacho por marcadores e
if constexpr
Em seguida, você se concentrará detalhadamente nos padrões clássicos de enable_if.
Perguntas Frequentes
A aula “SFINAE” é grátis?
Sim — o texto completo de “SFINAE” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C++ Academy, atualize para CoddyKit PRO. O curso de C++ Academy inclui 4 aulas no total.
O que vou aprender em “SFINAE”?
Habilite funções condicionalmente Você pratica C++ Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C++ Academy?
Nenhuma experiência prévia é necessária. C++ Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “SFINAE”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C++ Academy?
Sim. Cada aula de C++ Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.