Qual é a vantagem de std :: enable_if sobre static_assert para modelos de classe?
Eu queria saber sobre a vantagem de std::enable_ifover static_assertspara evitar a instanciação do template. Esta resposta sugere que std::enable_ifpermite SFINAE , que é um argumento convincente no caso de modelos de função .
No entanto, este argumento é legítimo para modelos de classe (e modelos de variáveis )? Pelo que eu sei, não há resolução de sobrecarga envolvida nisso, tornando SFINAE - mais uma vez, até onde eu sei - não relevante, mas posso estar errado. Se sim, você pode citar um exemplo?
Se não, suponho static_assertser a melhor solução para o problema em questão (evitando a instanciação do template) no caso de templates de classe, já que é indiscutivelmente mais explícito, conciso e legível e permite uma mensagem de erro customizada. Isso está correto ou estou perdendo um ponto diferente do SFINAE?
Respostas
Exemplo de como sobrecarregar classes usando SFINAE:
#include <type_traits>
#include <iostream>
template <typename, typename = void>
struct Foo;
template <typename Bar>
struct Foo <Bar, typename std::enable_if<std::is_same<Bar,int>::value>::type>
{
Foo ()
{
std::cout << "Hello ";
}
};
template <typename Bar>
struct Foo <Bar, typename std::enable_if<std::is_same<Bar,bool>::value>::type>
{
Foo ()
{
std::cout << "world!\n";
}
};
int main()
{
Foo<int>();
Foo<bool>();
}
Para casos em que você não deseja sobrecarregar, mas ainda deseja restringir a um conjunto de tipos, concordo que:
template <typename Bar>
class Foo
{
static_assert(
std::is_same<Bar,int>::value ||
std::is_same<Bar,bool>::value,
"Bar must be bool or int");
// class stuff
};
... é mais claro e simples do que:
template <typename Bar,
typename std::enable_if<
std::is_same<Bar,int>::value ||
std::is_same<Bar,bool>::value,
bool>::type = true>
class Foo
{
// class stuff
};
... especialmente porque com a segunda opção o compilador se refere a Fooobjetos com seu primeiro argumento e seu segundo argumento ( true, no nosso caso), que podem ser misteriosos para o usuário. Além disso, é mais complicado se você quiser que um cabeçalho manipule a classe com apenas uma declaração leve dele (veja como fazer isso aqui ).
No entanto, este argumento é legítimo para modelos de classe (e modelos de variáveis)? Pelo que eu sei, não há resolução de sobrecarga envolvida nisso, tornando SFINAE - mais uma vez, até onde eu sei - não relevante, mas posso estar errado. Se sim, você pode citar um exemplo?
Você pode se especializar em modelos de classe e o SFINAE pode ser usado para escolher entre as especializações. Ele também impedirá a instanciação de tal classe / sua especialização (até então, possivelmente mal formada), em vez de falhar na compilação devido a static_assert.
std :: enabled_if é usado em SFIANE para especialização de classes de modelo, métodos e .... static_assert é usado para verificar um contrato em tempo de compilação e fornecer uma mensagem de erro útil.