C ++ Nested Template

I have a template form template:

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

I would like to create a specific version of an example function for the case when ContainerType is a vector. Where Vector itself is a template class, but I do not know what type of values ​​this Vector has.

My intuition was to create this in the header file:

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

But it does not compile, and an error from clang:

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

Is it possible to use a different syntax?

+5
source share
3 answers

If you didn’t want to specialize in the template and were looking for specialization only for members, try the following

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

If you intend to specialize a function, I would just overload the function like this

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

This is mainly due to the fact that a full-text specification of function templates is not required. Overloading allows almost the same effects!

Note This is a great article related to your question! http://www.gotw.ca/publications/mill17.htm

+2
source

You can use the overload and send tags mechanism:

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

As skypjack said, this approach has little appeal when using const. If you are not using c++11 (I suspect you are not using it because you use the > > syntax for nested templates), you can work around this as follows:

 #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); } 
+2
source

Another way to approach this is composition.

The act of adding sample can be considered as a component of the implementation of the class. If we remove the implementation of adding a sample to this template class, we can only partially specialize this discrete component.

For instance:

 #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 // eg 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); } 
+1
source

All Articles