2013-03-03 17 views
6

C++ consente ai parametri del modello non di tipo di essere di tipo integrale o di enumerazione (con integrale compreso booleano e carattere), oltre a puntatori e riferimenti a tipi arbitrari.Caso di utilizzo per parametro modello non di tipo non di tipo integrale/enumerativo?

Ho visto i parametri interi, booleani e di enumerazione utilizzati ampiamente e apprezzo la loro utilità. Ho persino visto un uso intelligente dei parametri dei caratteri per compile-time parsing of strings.

Ma mi chiedo quali sono alcuni casi d'uso per i parametri del modello non di tipo che sono puntatori o riferimenti a tipi arbitrari?

+3

cercherà di trovare un buon esempio, ma i parametri del modello puntatore a funzione sono piuttosto utile –

risposta

4

L'utilizzo di una funzione puntatore-membro come parametro del modello consente al compilatore di effettuare una chiamata in linea a tale funzione. Un esempio di questo utilizzo può essere visto nella mia risposta a questa domanda: How to allow templated functor work on both member and non-member functions

In questo esempio, la funzione pointer-to-member nel parametro template abilita la generazione di una funzione 'thunk' che contiene una chiamata (inline) alla funzione pointer-to-member. Un puntatore alla funzione thunk ha una firma generica (e dimensioni fisse) che consente di memorizzarlo e copiarlo con un costo di runtime minimo, a differenza della funzione puntatore-membro.

+0

Interessante. Mi chiedo se 'std :: bind' fa, o potrebbe, fare uso di questa tecnica. Sai se le implementazioni di 'std :: bind' tipicamente memorizzano un puntatore a funzione membro nell'oggetto restituito da, ad esempio,' std :: bind (& SomeClass :: some_function, some_arg, _1) '? – HighCommander4

+0

'std :: bind' non può usare un puntatore a funzione membro come parametro di un modello non di tipo, perché prende il puntatore function function' & SomeClass :: some_function' come parametro di funzione, non come parametro di modello. – willj

+0

Certo, ma l'oggetto restituito da 'std :: bind()' potrebbe avere il puntatore alla funzione membro come parametro del modello non di tipo, e quindi evitare di memorizzare il puntatore della funzione membro, giusto? – HighCommander4

3

se si conosce l'indirizzo di un buffer in fase di compilazione, è possibile prendere una decisione (in fase di compilazione) in base al suo allineamento, soprattutto per cose come memcpy, questo consente di saltare qualsiasi controllo di runtime, e basta saltare direttamente alla copia dei dati utilizzando i tipi di dimensioni più efficienti.

(Sto indovinando) Si potrebbe anche essere in grado di compilare-asserire che un puntatore passato è allineato alla pagina (utile per esempio il protocollo nvme), anche se non so a priori come sarebbe.

2

Penso che l'argomento del modello di puntatore sia operazioni. (Dove il modo più circostanziato sarebbe un puntatore a funzione, e il modo più "facile" un oggetto funzione [che a sua volta è un tipo di nuovo.])

template<typename Key, class Val, bool (*CMP)(Key const&, Key const&)> 
class map 
{ 
}; 

template<typename KEY, class VALUE, typename CMP = std::less<KEY>> 
class map 
{ 
public: 
    CMP cmp; 
}; 

Dal momento che non so, che rispetto al applicare in anticipo, non è possibile costruirlo nel contenitore. È necessario che venga fornito esternamente a qualsiasi funzione che lo richiede o tramite un modello.

+0

Ci sono vantaggi della primo (puntatore di funzione) sul secondo (oggetto funzione)? – HighCommander4

+0

Non riesco a pensare a nessuno, è il contrario. L'oggetto funzione è più flessibile della sintassi del puntatore della funzione. – Pixelchemist

+0

Apparentemente è abbastanza tardi per essere stupido. Commento ritirato. – Casey

-1

Ecco un utile esempio di parametri di modello non integrali. Alcuni predeclarations (non tutti, ma quanto basta per ottenere l'idea):

template <bool flag, class T, class F> struct SelectType 
{ 
    typedef T Result; 
}; 
template <class T, class F> struct SelectType<false, T, F> 
{ 
    typedef F Result; 
}; 

#define PARAMETER(selector, type) typename SelectType<TypeTraits<T>::selector, type, 

#define PTR_TRAITS typename ::Linderdaum::Utils::TypeTraits<T>::PointeeType 
#define REF_TRAITS typename ::Linderdaum::Utils::TypeTraits<T>::ReferredType 

using namespace ::Linderdaum::Utils; 

template <class T> struct ParameterType 
{ 
    typedef 
    PARAMETER(IsString,   clStringParameter    ) 
    PARAMETER(IsReference,  clPODParameter<REF_TRAITS> ) 
    PARAMETER(IsPointer,  clPointerParameter<PTR_TRAITS>) 
    PARAMETER(IsFundamental, clPODParameter<T>    ) 
    // default 
    clPODParameter<T> 
    >::Result 
    >::Result 
    >::Result 
    >::Result 
    Type; 
}; 

E il codice effettivo utilizzo:

clParametersList Params; 

ParameterType<const LString& >::Type Param0; 
ParameterType<size_t >::Type Param1; 
ParameterType<clDownloadCompleteCallback >::Type Param2; 

Param0.ReadValue(&P0); 
Param1.ReadValue(&P1); 
Param2.ReadValue(&P2); 

Params.push_back(&Param0); 
Params.push_back(&Param1); 
Params.push_back(&Param2); 
+2

Dov'è il parametro template non-non-integral in questo codice? – HighCommander4

2

Ho usato un invadente (puntatori ai dati memorizzati negli elementi di dati) elenco collegato in precedenza, che era parametrizzato da un puntatore al membro dei dati che indicava dove l'elenco memorizzava i suoi collegamenti. Che parametrizzazione consente di memorizzare lo stesso dato in più elenchi se usano diversi elementi di collegamento:

template <class T, T* (T::*Link)> class ilist; 

struct Node { 
    Node* a_next; 
    Node* b_next; 
}; 

typedef ilist<Node, &Node::a_next> a_list; 
typedef ilist<Node, &Node::b_next> b_list; 
Problemi correlati