Domanda

In C # possiamo definire un tipo generico che impone vincoli sui tipi che possono essere usati come parametro generico. L'esempio seguente illustra l'utilizzo di vincoli generici:

interface IFoo
{
}


class Foo<T> where T : IFoo
{
}

class Bar : IFoo
{
}

class Simpson
{
}

class Program
{
    static void Main(string[] args)
    {
        Foo<Bar> a = new Foo<Bar>();
        Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
    }
}

Esiste un modo per imporre vincoli per i parametri del modello in C ++.


C ++ 0x ha il supporto nativo per questo, ma sto parlando dell'attuale C ++ standard.

È stato utile?

Soluzione

Come ha già detto qualcun altro, C ++ 0x lo sta incorporando nel linguaggio. Fino ad allora, consiglierei Bjarne Stroustrup 's suggerimenti per i vincoli del modello .

Modifica: Boost ha anche un alternativa a sé .

Modifica2: sembra che i concetti di sono stati rimossi da C ++ 0x .

Altri suggerimenti

Se usi C ++ 11, puoi usare static_assert con std :: is_base_of per questo scopo.

Ad esempio,

#include <type_traits>

template<typename T>
class YourClass {

    YourClass() {
        // Compile-time check
        static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");

        // ...
    }
}

" Implicitamente " è la risposta corretta. I modelli creano in modo efficace una "digitazione anatra" scenario, a causa del modo in cui sono compilati. È possibile chiamare qualsiasi funzione desiderata su un valore tipizzato dal modello e le uniche istanze che verranno accettate sono quelle per le quali viene definito quel metodo. Ad esempio:

template <class T>
int compute_length(T *value)
{
    return value->length();
}

Possiamo chiamare questo metodo su un puntatore a qualsiasi tipo che dichiari il metodo length () per restituire un int . Questa convenzione:

string s = "test";
vector<int> vec;
int i = 0;

compute_length(&s);
compute_length(&vec);

... ma non su un puntatore a un tipo che non dichiara length () :

compute_length(&i);

Questo terzo esempio non verrà compilato.

Funziona perché C ++ compila una nuova versione della funzione (o classe) templatizzata per ogni istanza. Durante l'esecuzione di tale compilazione, effettua una sostituzione diretta, quasi a macroistruzione, dell'istanza del modello nel codice prima del controllo del tipo. Se tutto funziona ancora con quel modello, la compilazione procede e alla fine arriviamo a un risultato. Se qualcosa fallisce (come int * non dichiara length () ), allora otteniamo il temuto errore di compilazione del modello di sei pagine.

Puoi mettere un tipo di guardia su IFoo che non fa nulla, assicurati che sia lì su T in Foo:

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}

Scopri Boost

  

The Boost Concept Check Library (BCCL)

     

La libreria Concept Check consente di aggiungere dichiarazioni esplicite e il controllo di concept nello stile della estensione del linguaggio C ++ proposta .

Sorta di. Se static_cast su un IFoo *, sarà impossibile creare un'istanza del modello a meno che il chiamante non passi una classe che può essere assegnata a un IFoo *.

Solo implicitamente.
Qualsiasi metodo utilizzato in un metodo effettivamente chiamato viene imposto al parametro template.

Puoi farlo. Crea il modello di base. Fallo avere solo costruttori privati. Quindi crea specializzazioni per ogni caso che desideri consentire (o fai il contrario se l'elenco non consentito è molto più piccolo dell'elenco consentito).

Il compilatore non ti consentirà di creare un'istanza dei modelli che utilizzano la versione con costruttori privati.

Questo esempio consente solo l'istanza con int e float.

template<class t> class FOO { private: FOO(){}};

template<> class FOO<int>{public: FOO(){}};

template<> class FOO<float>{public: FOO(){}};

Non è un modo breve ed elegante per farlo, ma è possibile.

Guarda il pattern CRTP (Curiously Recursive Template Pattern). È progettato per supportare l'ereditarietà statica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top