Qual é a vantagem de std :: enable_if sobre static_assert para modelos de classe?

Aug 31 2020

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

5 Elliott Aug 31 2020 at 18:20

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 ).

3 Fureeish Aug 31 2020 at 17:28

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.

apramc Aug 31 2020 at 23:25

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.