Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization of particular members?

Tags:

Is it possible to specialize particular members of a template class? Something like:

template <typename T,bool B> struct X {     void Specialized(); };  template <typename T> void X<T,true>::Specialized() {     ... }  template <typename T> void X<T,false>::Specialized() {     ... } 

Ofcourse, this code isn't valid.

like image 396
sold Avatar asked Oct 01 '09 00:10

sold


People also ask

What is a template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What is the specialty of a template function give example?

Template in C++is a feature. We write code once and use it for any data type including user defined data types. For example, sort() can be written and used to sort any data type items. A class stack can be created that can be used as a stack of any data type.

Why do we need template specialization?

Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.


1 Answers

You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.

template <typename T,bool B> struct X {     void Specialized(); };  // works template <> void X<int,true>::Specialized() {     ... } 

A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs

// "maps" a bool value to a struct type template<bool B> struct i2t { };  template <typename T,bool B> struct X {     void Specialized() { SpecializedImpl(i2t<B>()); }  private:     void SpecializedImpl(i2t<true>) {        // ...     }      void SpecializedImpl(i2t<false>) {        // ...     } }; 

Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately

template<typename T, bool B> struct SpecializedImpl;  template<typename T> struct SpecializedImpl<T, true> {   static void call() {      // ...   } };  template<typename T> struct SpecializedImpl<T, false> {   static void call() {      // ...   } };  template <typename T,bool B> struct X {     void Specialized() { SpecializedImpl<T, B>::call(); } }; 

I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.

You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)

template <typename T,bool B> struct X { private:     // maps a type and non-type parameter to a struct type     template<typename T, bool B>     struct SpecializedImpl { };  public:     void Specialized() { Specialized(SpecializedImpl<T, B>()); }  private:     template<typename U>     void Specialized(SpecializedImpl<U, true>) {       // ...     }      template<typename U>     void Specialized(SpecializedImpl<U, false>) {       // ...     } }; 

I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.

like image 135
Johannes Schaub - litb Avatar answered Sep 25 '22 02:09

Johannes Schaub - litb