Qual è il vantaggio di std :: enable_if rispetto a static_assert per i modelli di classe?

Aug 31 2020

Mi chiedevo quale fosse il vantaggio di std::enable_ifoltre static_assertsper impedire la creazione di istanze del modello. Questa risposta suggerisce, che std::enable_ifconsente SFINAE , che è un argomento convincente nel caso dei modelli di funzione .

Tuttavia questo argomento è legittimo per i modelli di classe (e per i modelli di variabili )? Per quanto ne so, non è coinvolta alcuna risoluzione del sovraccarico, rendendo SFINAE - ancora una volta, per quanto ne so - non rilevante, ma potrei sbagliarmi. In caso affermativo, puoi citare un esempio?

In caso contrario, presumo static_assertche sia la soluzione migliore per il problema dato (impedendo l'istanza del modello) nel caso di modelli di classe, poiché è probabilmente più esplicito, conciso e leggibile e consente un messaggio di errore personalizzato. È corretto o mi manca un punto diverso da SFINAE?

Risposte

5 Elliott Aug 31 2020 at 18:20

Esempio di come sovraccaricare le classi utilizzando 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>();
}

Per i casi in cui non si desidera eseguire il sovraccarico ma si desidera comunque limitare a un insieme di tipi, sono d'accordo che:

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
};

... è più chiaro e più semplice di:

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
};

... soprattutto perché con la seconda opzione il compilatore fa riferimento agli Foooggetti con il loro primo argomento e il loro secondo argomento ( true, nel nostro caso), che possono essere misteriosi per l'utente. Inoltre, è più complicato se si desidera che un'intestazione gestisca la classe con solo una sua dichiarazione leggera (vedere come farlo qui ).

3 Fureeish Aug 31 2020 at 17:28

Tuttavia questo argomento è legittimo per i modelli di classe (e per i modelli di variabili)? Per quanto ne so, non è coinvolta alcuna risoluzione del sovraccarico, rendendo SFINAE - ancora una volta, per quanto ne so - non rilevante, ma potrei sbagliarmi. In caso affermativo, puoi citare un esempio?

Puoi specializzare i modelli di classe e SFINAE può essere utilizzato per scegliere tra le specializzazioni. Impedirà anche la creazione di istanze di tale classe / specializzazione (per allora, forse mal formata), invece di non riuscire a compilare a causa di static_assert.

apramc Aug 31 2020 at 23:25

std :: enabled_if viene utilizzato in SFIANE per la specializzazione di classi, metodi e .... static_assert viene utilizzato per controllare un contratto in fase di compilazione e fornire un utile messaggio di errore.