traits: Traits technical study notes

Traits: A Preliminary Study of Traits Technology

Overview :
Traits is a feature extraction technique , which is widely used in Generic Programming and is often used to make different types available for the same operation , or to provide different implementations for different types . Traits are often required in the implementation process The following three basic features of C ++ are used :
enum
typedef
template
 ( partial )  specialization
Among them :
enum
is used to unify the symbols that change between different types into one , it is often used in C ++ to replace in a class define , you can call an enum a define in a class ;
typedefs
are used to define the form your template class supports for a feature. Your template class must support a feature in some form , otherwise the type extractor traits will not work properly . See here you might think, is it too harsh ? In fact , not supporting a certain feature itself is a way to support ( see example 2 , we define two types of flags , __xtrue_type and __xfalse_type , which respectively indicate support and non-support for a certain feature ).
template
 ( partial )  specialization is used to provide the correct or more appropriate version for a specific type .
With the help of a few simple techniques above , we can use traits to extract the characteristics defined in the class and provide different implementations based on different characteristics . You can From the definition of characteristics to extraction , to the actual use of traits, it is collectively referred to as traits technology , but this definition makes traits too complicated . I prefer to limit the definition of traits to characteristic extraction , because this definition makes traits appear simpler . Easier to understand , ^ _ ^.

Example : As  mentioned
above , traits can be used to provide different implementations for different types , so here are two examples to illustrate how to achieve this . ( including ordinary int / long ..., the complex type CComplexObject that provides the clone method , and the function clone that is derived from this class ) , let's first consider the solution using the OO method . See the front Conditions , the first thing that jumps into your mind must be Interface , pure  virtual  function, etc. For our own designed class CComplexObject , this is not a problem , but what about basic data types ?

And what about complex types that don't provide a clone method ? ( At this point you may be thinking how easy it would be to Java , all classes are derived from Object by default , and Object already provides a default clone method , but , to make the class To really support clone , it must also implements Cloneable , so it ca n't avoid the troubles encountered here .
Here is a possible solution :

template <typename T, bool isClonable>
class XContainer
{
     ...
     void clone(T* pObj)
     {
         if (isClonable)
         {
             pObj->clone();
         }
         else
         {
             //... non-Clonable algorithm ...
         }
     }
};
But as long as you test it , this code doesn't compile . Why does this happen ? The reason is simple : the sentence pObj -> clone is illegal for non-Clonable classes or primitive types that do not implement the clone method . So how to solve the above What about this problem ? The above code that cannot be compiled tells us that to make our code compile , we cannot make pObj -> clone appear in the code of non-Clonable classes or basic types , that is, we need to provide different implementations for different types . In order to achieve this , we can define a trait with enum in our template class to indicate whether the class is a Clonable class , and then introduce a traits extraction class Traits inside the original template class , and by specilizing this class ,
To provide different implementations according to different traits . The specific implementation is as follows :
#include <iostream>
using namespace std;

class CComplexObject // a demo class
{
public:
     void clone() { cout << "in clone" << endl; }
};

// Solving the problem of choosing method to call by inner traits class
template <typename T, bool isClonable>
class XContainer
{
public:
     enum {Clonable = isClonable};

     void clone(T* pObj)
     {
         Traits<isClonable>().clone(pObj);
     }

     template <bool flag>
         class Traits
     {
     };

     template <>
         class Traits<true>
     {
     public:
         void clone(T* pObj)
         {
             cout << "before cloning Clonable type" << endl;
             pObj->clone();
             cout << "after cloning Clonable type" << endl;
         }
     };

     template <>
         class Traits<false>
     {
     public:
         void clone(T* pObj)
         {
             cout << "cloning non Clonable type" << endl;
         }
     };
};

void main()
{
     int* p1 = 0;
     CComplexObject* p2 = 0;

     XContainer<int, false> n1;
     XContainer<CComplexObject, true> n2;

     n1.clone(p1);
     n2.clone(p2);
}
Compiling and running it , the above program outputs the following result :
doing something non Clonable
before doing something Clonable
in clone
after doing something Clonable
This shows that we have successfully selected different operations for the template instance based on the passed in isClonable template parameter , while ensuring that In the case of the same interface , different implementations are provided for different types .

Example  2 :
Let's make some restrictions on the above example , assuming that our clone operation only involves basic types and CComplexObject and its derived classes , then we can further give The following solution :
#include <iostream>
using namespace std;

struct __xtrue_type { }; // define two mark-type
struct __xfalse_type { };

class CComplexObject // a demo class
{
public:
     virtual void clone() { cout << "in clone" << endl; }
};

class CDerivedComplexObject : public CComplexObject // a demo derived class
{
public:
     virtual void clone() { cout << "in derived clone" << endl; }
};

// A general edtion of Traits
template <typename T>
struct Traits
{
     typedef __xfalse_type has_clone_method; // trait 1: has clone method or not? All types defaultly has no clone method.
};

// Specialized edtion for ComplexObject
template <>
struct Traits<CComplexObject>
{
     typedef __xtrue_type has_clone_method;
};

template <typename T>
class XContainer
{
     template <typename flag>
         class Impl
     {
     };
     template <>
         class Impl <__xtrue_type>
     {
     public:
         void clone(T* pObj)
         {
             pObj->clone();
         }
     };
     template <>
         class Impl <__xfalse_type>
     {
     public:
         void clone(T* pObj)
         {
         }
     };
public:
     void clone(T* pObj)
     {
         Impl<Traits<T>::has_clone_method>().clone(pObj);
     }
};

void main()
{
     int* p1 = 0;
     CComplexObject c2;
     CComplexObject* p2 = &c2;
     CDerivedComplexObject c3;
     CComplexObject* p3 = &c3; // you must point to a derived object by a base-class pointer,
                             //it's a little problem

     XContainer<int> n1;
     XContainer<CComplexObject> n2;
     XContainer<CComplexObject> n3;

     n1.clone(p1);
     n2.clone(p2);
     n3.clone(p3);
}
Now , all basic types and the CComplexObject class system can be used for XContainer .

Conclusion :
When you see this , you may say that traits are nothing more than that, and you think they are some advanced stuff ! In fact, the technology is like this , and it is very easy to put it bluntly . , the key is how to use them in practice and serve the actual Designing / Development . After all , in the IT field , there is no value in technology that cannot be applied to actual .

Reference link: http://www.cppblog.com/woaidongmao/archive/2008/11/09/66387.html


When I watched "modern c++ design" today, I found that I had forgotten the Traits technology that I had managed to understand before. Really... I learned it again and quickly wrote it down.
Traits technology can be used to obtain a type of related information. First, suppose there is the following generic iterator class, where the type parameter T is the type pointed to by the iterator:

template <typename T>
class myIterator
{
...
};
When we use myIterator, how can we know the type of the element it points to? We can add an inline type to this class like this:
template <typename T>
class myIterator
{
typedef T value_type; 
...
};
In this way, when we use the myIterator type, we can get the type pointed to by the corresponding myIterator through myIterator::value_type.

Now let's design an algorithm that uses this information.
template <typename T>
typename myIterator<T>::value_type Foo(myIterator<T> i)
{
...
}
Here we define a function Foo, whose return is the type pointed to by the parameter i, which is T, so why do we still use that value_type? That's because, when we want to modify the Foo function to work with all types of iterators, we can write:
template <typename I> //这里的I可以是任意类型的迭代器
typename I::value_type Foo(I i)
{
...
}
Now, any iterator that defines the value_type embedded type can be used as the parameter of Foo, and the type of the return value of Foo will be the same as the type of the element pointed to by the corresponding iterator. So far everything seems to be resolved, we are not using any special techniques. However, when considering the following situations, a new problem emerges:

raw pointers can also be used as iterators, but we obviously have no way to add an embedded type of value_type to raw pointers, so that our Foo The () function cannot be applied to native pointers, which is a big shortcoming. So what is the solution to this problem? At this point is our protagonist: the type information extraction machine Traits comes on stage

....drum roll...

We can not use the value_type of myIterator directly, but extract this information through another class :
template <typename T>
class Traits
{
typedef typename T::value_type value_type;
};
In this way, we can get the value_type of myIterator through Traits<myIterator>::value_type, so we rewrite the Foo function as:
template <typename I> //这里的I可以是任意类型的迭代器
typename Traits<I>::value_type Foo(I i)
{
...
}
However, even so, the problem of the native pointer is still not solved, because the Trait class has no way to obtain the relevant information of the native pointer. So we offer another weapon of C++ - partial specialization:
template <typename T>
class Traits<T*> //注意 这里针对原生指针进行了偏特化
{
typedef typename T value_type;
};
With the partial specialization of Traits above, we state the fact that the element pointed to by a pointer of type T* is of type T.

In this way, our Foo function can fully apply to raw pointers. For example:
int * p;
....
int i = Foo(p);
Traits will automatically deduce that the type of the element pointed to by p is int, so Foo returns correctly.

Traits related summary:
1.typedef can be defined in class or struct
template<T>
class CXX
{
typedef T value_type;
};
Likewise, templates can embed templates!
2. Seeing template<> is mostly in template specialization. Specialization is divided into full specialization, partial specialization, etc. Keep this in mind, otherwise you won't understand something.
3.Template is actually an extension of the compiler, allowing the code to be automatically generated. Its functionality is equivalent to something like #define. To put it bluntly, these things of C++ are to make your code reusable and reduce unnecessary programming in the future.
4.traits As far as we can currently use it, it can unify the interface and make your template compatible with basic types.
5. An example assumption:
like WINAPI often provides XxA and XxW, the call should be decided according to the ASCII code or UNICODE code used. Then you can use template to cooperate with traits to achieve it - it is not possible to use template alone. ASCII and UNICODE may be different in some places, and traits will be used in these places.
Quoting several articles:
"C++ Traits" http://www.cnblogs.com/hush/archive/2004/03/10/2717.html
"The Essence of Type Traits" http://blog.csdn.net /sanlongcai/archive/2007/09/15/1786647.aspx
"traits: A Preliminary Study of Traits Technology" http://www.cppblog.com/woaidongmao/archive/2008/11/09/66387.html (this is true very good!)


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324365194&siteId=291194637