[C ++ template tour] This project uses the C ++ template (traits) and
Problems and requirements:
Let's take a look at this article. A tour of the C ++ template project experiences using the C ++ template (traits. I will give a new idea for the question raised in this article.
Talking is cheap, show me the code.
Code:
class ExportData{ union { string * sp; long* lp; double* dp; void* vp; }; enum my_type {SP,LP,DP} types; static unordered_map<type_index,my_type> typeMap;public: template <typename T> ExportData(T t) { if(typeMap.find(typeid(t))==typeMap.end()) assert(false); vp=new T(t); types= typeMap[typeid(T)]; } template <typename T> void setData(T t) { if(typeMap.find(typeid(t))==typeMap.end()) assert(false); switch(types) { case SP: delete sp; break; case DP: delete dp; break; case LP: delete lp; break; } vp=new T(t); types=typeMap[typeid(T)]; } template <typename T> void getData(T& t) { if(typeMap[typeid(T)]!=types) assert(false); t=*(static_cast<T*>(vp)); } }; unordered_map<type_index,ExportData::my_type> ExportData::typeMap{ {typeid(string),ExportData::my_type::SP}, {typeid(long),ExportData::my_type::LP}, {typeid(double),ExportData::my_type::DP},};
Repeat the following four requirements:
1. ExportData only supports four types of operations: INTEGER (long), floating point (double), string (string), and binary (void *, size. (I did not consider binary) 2. the size of the ExportData structure should be considered to minimize space redundancy (I use a consortium to save pointers to various types of data. even if you operate on the four data types above, you still want to unify the methods used when you Get or Set real data from ExportData (the methods are obviously unified, because the template is used) 4. when the caller tries to use a data type other than the above four types, the caller can be notified of the Type Mismatch by returning an error (for the convenience of demonstration, trying to use another type will cause the assertion to fail, stop running)
If you also hate the existence of swtich in the code, you can use the table-driven method again. The Code is as follows:
Class DeleteLong {public: void operator () (void * p) {delete static_cast <long *> (p) ;}}; class DeleteString {public: void operator () (void * p) {delete static_cast <string *> (p) ;}}; class DeleteDouble {public: void operator () (void * p) {delete static_cast <double *> (p) ;}}; class ExportData {union {string * sp; long * lp; double * dp; void * vp ;}; enum my_type {SP, LP, DP} types; // change it to object. static uno Rdered_map <type_index, my_type> typeMap; static vector <function <void (void *)> deleters; public: template <typename T> ExportData (T t T) {static_assert (is_same <T, string >:: value | is_same <T, double >:: value | is_same <T, long >:value, "never support! "); // Thank Cui Fangfang
// If (typeMap. find (typeid (t) = typeMap. end () // assert (false); vp = new T (t); types = typeMap [typeid (T)];} template <typename T> void setData (T t) {if (typeMap. find (typeid (t) = typeMap. end () assert (false); (deleters [types]) (vp); vp = new T (t); types = typeMap [typeid (T)];} template <typename T> void getData (T & t) {if (typeMap [typeid (T)]! = Types) assert (false); t = * (static_cast <T *> (vp ));}
// Here you can change it to overload, void getData (long & t ){...} void getData (sting & t ){....} void getData (double & t ){...} compilation error when calling other types}; unordered_map <type_index, ExportData: my_type> ExportData: typeMap {typeid (string), ExportData: my_type: SP }, {typeid (long), ExportData: my_type: LP}, {typeid (double), ExportData: my_type: DP },}; vector <function <void (void *)> ExportData: deleters {DeleteString (), DeleteLong (), DeleteDouble (),};
Here is the test code:
int main(){ long i=5; long j=0; string s="Hello"; string ss; ExportData p(i); p.setData(++i); p.getData(j); p.setData(s); p.getData(ss); cout<<j<<endl; cout<<ss<<endl; return 0;}
This is a lite version that uses heavy load:
Class ExportData {union {string * sp; long * lp; double * dp;}; public: ExportData (long t) {lp = new long (t );} exportData (double t) {dp = new double (t);} ExportData (string t) {sp = new string (t);} void setData (long t) {* lp = t;} void setData (double t) {* dp = t;} void setData (string t) {* sp = t;} void getData (long & t) {t = * lp;} void getData (double & t) {t = * dp;} void getData (string & t) {t = * sp ;}// 1. The Destructor needs to solve the memory leakage problem. 2. If the current Pointer Points to double, the setData function will input a string, and a memory error will occur .};
This version has two serious problems. 1. The Destructor needs to solve the memory leakage problem. 2. If the current Pointer Points to double and the setData function imports a string, a memory error will occur.
In my opinion, the second error cannot prevent users from compiling during the compilation period, because during setData, they cannot know which pointer is valid during the compilation period.
Additional advantages of this Code: 1. The code is shorter and more compact. (Reduced code)
2. The ExportData object is easier to use.
3. The ExportData object has only two data items, one is the pointer union and the other is the enumeration value. (Better performance)
4. I added an additional feature based on the author's 4-point requirement. ExportData can dynamically change the type of data held. (More powerful)
5. if you do not use templates but use heavy loads for all methods in the class, although this will increase the amount of code, the advantage is that we can prompt the user that ExportData does not support some types during compilation, it can also increase the running speed. If you want to do this, you can analyze the specific problem.
6. Because templates are used, they are highly scalable. When adding support types, you only need to modify a small amount of code. (Better scalability)
Finally, this code is a sample code, which may not be able to be repeated. If I reference the original author, "I think there must be a better solution, for example, you can try to prompt that the type is not supported during compilation instead of returning an error at runtime. If you have a better solution, please join us .", Me too.