2016-07-01 67 views
5

ho una classe template del modulo:nidificate template C++

template<typename ContainerType> 
class ConfIntParamStat { 
    public: 
    typedef typename ContainerType::Type Type; 
... 
    private: 
    void sample(int iteration) {...} 
} 

vorrei creare una versione specifica del campione funzione per il caso in cui containerType è un vettore. Dove Vector stesso è una classe template, ma non conosco il tipo di valori di questo vettore.

La mia intuizione è stato quello di creare questa nel file di intestazione:

template<typename Type> 
ConfIntParamStat<Vector<Type> >::sample(int iteration) { 
... 
} 

Ma non si compila, e l'errore da clang è:

error: nested name specifier 'ConfIntParamStat<Vector<Type> >::' for declaration does not refer into a class, class template or class template partial specialization 

E 'possibile utilizzare un altro sintassi?

+6

Non si può specializzare un membro di una classe template. Devi specializzare l'intera classe. Se vuoi davvero specializzare solo un membro, allora crea una funzione di supporto che la funzione membro della classe chiama e sovraccarica o specializza. –

+0

Puoi diramare il tuo 'esempio' con' if (std :: is_same :: value) '? (supponendo che ci sia 'Type' in' Vector') – mvidelgauz

+1

@DarkFalcon: Spot on. Vorrei forse modificare il tuo commento dicendo "Non puoi * parzialmente * specializzare un membro di una classe template." Se lo specializzi completamente, allora funzionerebbe. Modifica: [esempio] (http://coliru.stacked-crooked.com/a/b83a79e4e01b0e03) – AndyG

risposta

2

se non ha ancora desidera specializzarsi il modello e sono stati alla ricerca di un unico membro di specializzazione provare il seguente

#include <iostream> 
#include <vector> 
using namespace std; 

template <typename ContainerType> 
class Something { 
    public: 

    void do_something(int); 

    template <typename Which> 
    struct do_something_implementation { 
     void operator()() { 
      cout << "general implementation" << endl; 
     } 
    }; 
    template <typename Which> 
    struct do_something_implementation<vector<Which>> { 
     void operator()() { 
      cout << "specialized implementation for vectors" << endl; 
     } 
    }; 
}; 

template <typename ContainerType> 
void Something<ContainerType>::do_something(int) { 
    do_something_implementation<ContainerType>{}(); 
} 

int main() { 
    Something<double> something; 
    something.do_something(1); 

    return 0; 
} 

Se il vostro intento è quello di specializzarsi una funzione, vorrei solo sovraccaricare la funzione in questo modo

#include <iostream> 
#include <vector> 
using namespace std; 

template <typename ContainerType> 
class Something { 
    public: 

    void do_something(int); 

    template <typename Type> 
    void do_something(const vector<Type>&); 
}; 

template <typename ContainerType> 
void Something<ContainerType>::do_something(int) { 
    cout << "Called the general method for do_something" << endl; 
} 

template <typename ContainerType> 
template <typename Type> 
void Something<ContainerType>::do_something(const vector<Type>&) { 
    cout << "Called the specialised method" << endl; 
} 

int main() { 
    vector<int> vec{1, 2, 3}; 
    Something<double> something; 
    something.do_something(1); 
    something.do_something(vec); 

    return 0; 
} 

Questo è principalmente il motivo per cui non sono richieste specializzazioni template complete/esplicite. Il sovraccarico consente quasi gli stessi effetti!

Note Questo è un ottimo articolo correlato alla tua domanda! http://www.gotw.ca/publications/mill17.htm

+0

ha anche' int' come parametro ... –

+1

@ W.F. Grazie! Ho modificato la risposta – Curious

2

Si potrebbe fare ricorso al meccanismo di sovraccarico e tag la spedizione:

#include <vector> 

template <class T> 
struct Tag { }; 

template<typename ContainerType> 
class ConfIntParamStat { 
    public: 
    typedef typename ContainerType::value_type Type; 
//... 
// private: 
    void sample(int iteration) { 
     sample_impl(Tag<ContainerType>(), iteration); 
    } 

    template <class T> 
    void sample_impl(Tag<std::vector<T> >, int iteration) { 
     //if vector 
    } 

    template <class T> 
    void sample_impl(Tag<T>, int iteration) { 
     //if not a vector 
    } 
}; 

int main() { 
    ConfIntParamStat<std::vector<int> > cips; 
    cips.sample(1); 
} 

Come accennato skypjack questo approccio ha un po 'pareggio quando si usa const. Se non si utilizza c++11 (ho il sospetto tu non perché si utilizza > > sintassi per modelli annidati) si potrebbe risolvere questo come segue:

#include <iostream> 
#include <vector> 

template <class T> 
struct Tag { }; 

template <class T> 
struct Decay { 
    typedef T Type; 
}; 

template <class T> 
struct Decay<const T> { 
    typedef T Type; 
}; 

template<typename ContainerType> 
class ConfIntParamStat { 
    public: 
    typedef typename ContainerType::value_type Type; 
//... 
// private: 
    void sample(int iteration) { 
     sample_impl(Tag<typename Decay<ContainerType>::Type>(), iteration); 
    } 

    template <class T> 
    void sample_impl(Tag<std::vector<T> >, int iteration) { 
     std::cout << "vector specialization" << std::endl; 
    } 

    template <class T> 
    void sample_impl(Tag<T>, int iteration) { 
     std::cout << "general" << std::endl; 
    } 
}; 

int main() { 
    ConfIntParamStat<const std::vector<int> > cips; 
    cips.sample(1); 
} 
+1

Usa 'decay_t' come' sample_impl (Tag >(), iterazione) 'oi tratti preferisci. Altrimenti non funzionerà con 'ConfIntParamStat > cips;', ad esempio. – skypjack

+0

@skypjack modificato :) –

+0

perché non usi 'std :: decay'? Non funziona ancora per il tipo 'const std :: vector &', ad esempio. – skypjack

1

Un altro modo per avvicinarsi a questo è la composizione.

L'atto di aggiungere uno sample può essere considerato come un componente dell'implementazione della classe. Se rimuoviamo l'implementazione dell'aggiunta di un campione in questa classe template, possiamo quindi parzialmente specializzare solo questo componente discreto.

Ad esempio:

#include <vector> 

// 
// default implementation of the sample component 
// 
template<class Outer> 
struct implements_sample 
{ 
    using sample_implementation = implements_sample; 

    // implements one function 
    void sample(int iteration) { 
    // default actions 
    auto self = static_cast<Outer*>(this); 
    // do something with self 
    // e.g. self->_samples.insert(self->_samples.end(), iteration); 
    } 
}; 

// refactor the container to be composed of component(s) 
template<typename ContainerType> 
class ConfIntParamStat 
: private implements_sample<ConfIntParamStat<ContainerType>> 
{ 
    using this_class = ConfIntParamStat<ContainerType>; 
    public: 

    // I have added a public interface  
    void activate_sample(int i) { sample(i); } 

    // here we give the components rights over this class   
    private: 
    friend implements_sample<this_class>; 
    using this_class::sample_implementation::sample; 

    ContainerType _samples; 
}; 

// 
// now specialise the sample function component for std::vector 
// 
template<class T, class A> 
    struct implements_sample<ConfIntParamStat<std::vector<T, A>>> 
    { 
    using sample_implementation = implements_sample; 
    void sample(int iteration) { 
    auto self = static_cast<ConfIntParamStat<std::vector<T, A>>*>(this); 
    // do something with self 
    self->_samples.push_back(iteration); 
    } 
}; 



int main() 
{ 
    ConfIntParamStat< std::vector<int> > cip; 
    cip.activate_sample(1); 
    cip.activate_sample(2); 

}