In business logic, many logically different types of things often degrade to one type in programming languages. The simplest example is currency. We usually use a type for programming, such as double (some systems have a special currency type, here we use double for convenience) to represent the currency. However, the currency problem arises. There is a conversion problem between different currencies, that is, the exchange rate. For example, we have two currencies: RMB and USD. Although they are all currencies (the same type in the Code), we cannot directly assign values to them: Double RMB _; double USD _ = 100; RMB _ = USD _; // No. The value of USD 100 is equivalent to RMB 768, although the exchange rate must be converted to RMB _ = USD _ * e_rate; and e_rate is the exchange rate. Everyone knows this. Logically, USD 100 and USD 768 are equivalent (assuming today's exchange rate is 7.68) and can be exchanged. However, in software, we cannot simply assign values and must convert them. Now we want to use the code to directly express the logic meaning, that is, to use the value assignment operation: = to realize the conversion between currencies. What should we do? Ah, yes, Operator overloading. We can reload the operator = Operator to enable the exchange rate conversion function. (Someone may raise an objection to changing the semantics of an operator and whether it violates the teachings of masters. However, I personally think that semantics should follow the business logic. Since the meaning of logic is heavy-loaded, no dispute should be caused. Otherwise, what else should I do ?) But the problem is that the overload depends on different types. The double operator = (double) operator is defined by default and already exists and cannot be reloaded in the same form. Besides, even if it is okay, how can we distinguish between two types of conversions if the Copied object and the assigned object are of the same type? Obviously, we need a new type. Typedef is definitely not expected because it only alias A type and does not generate a new type. Therefore, we can only turn to class. We can define different currency classes as follows: Class RMB {public: Double _ Val ;}; class USD {public: Double _ Val ;};... In this way, operator =: Class RMB {public: RMB operator = (const RMB & V) {_ Val = v. _ Val;} RMB operator = (const USD & V) {_ Val = v. _ Val * e_rate; // currency conversion} public: Double _ Val;}; Class USD {public: USD operator = (const USD & V) {_ Val = v. _ Val;} USD operator = (const RMB & V) {_ Val = v. _ Val/e_rate; // currency conversion} public: Double _ Val;}; so that we can assign values to the two currencies: RMB _; USD _; RMB _ = USD _; // value assignment operation with currency conversion. Based on this method, we continue to push down and can construct various currencies and define them. Conversion between them: Class UKP // GBP {...} Class jpd // yen {...}... But there is a problem. If there are 10 currencies, we must define 100 operator = reloads, and all of them are repetitive code. This is too stupid. We must adopt better methods to achieve our ideal. Note that every currency code conforms to the same pattern and has a strong regularity. As you can see, this situation is very suitable for the use of the C ++ super weapon-template. That's right. Just do it: Template <int currtype> class currency {public: Double _ Val;}; note that a feature of the template is not conventional here: the non-type template parameter is the int currtype. Template parameters are usually of the same type, such as Int. But it can also be a non-type template parameter, just like the currtype here. Traditionally, non-type template parameters are used to pass a static value to construct a template class. However, this template parameter is not used by the template and will never be used. The role of this template parameter is "manufacturing type": typedef currency <0> RMB; // RMB typedef currency <1> USD; // USD typedef currency <2> UKP; // pound typedef currency <3> jpd; // yen... Typedef itself does not produce new types, but here currency <
N> It is already a completely different type. When a template is instantiated into a class, as long as the real parameters of the template parameters are different, it is a different type. We have used this feature of the template to create a model that has the same structure but is completely independent. Okay. The next step is to reload operator = Operator. Of course, it cannot be a silly thing to reload operator = for every pair of currency types. You can use a member function template to solve the problem: Double e_rate [10] [10]; // Exchange Rate Table template <int currtype> class currency {public: template <int CT2> currency <currtype> & operator = (count currency <CT2> & V) {_ Val = v. _ Val * e_rate [CT2] [currtype]; // find the corresponding exchange rate in the Exchange Rate Table, // calculate and assign values} public: Double _ Val ;}; in the operator = code, the value of the value assignment object V is multiplied by an exchange rate, which is stored in the Exchange Rate Table and retrieved through the template parameters currtype and CT2 (of course, the Exchange Rate Table is large enough ). In this way, we can assign values without having to worry about currency conversion: // initialize the e_rate [0] [0] = 1; e_rate [1] [0] = 7.68 ;... // Use the currency USD _; UKP _; jpd _ = USD _ = UKP = RMB _; // success! Everything goes well. It should be noted that the exchange rate table is not initialized when it is declared, because the exchange rate changes frequently and should not be written into the code as a constant. Further, you can use a class to encapsulate a variable-size exchange rate table, or even use a file or database to initialize it. Of course, the problem is that currency is involved in calculation, otherwise it will be useless. Therefore, we have to make these currencies have basic computing capabilities. The Calculation of currency should have the following capabilities according to the business logic: 1. +,-: addition and subtraction of the two currencies. different currencies are allowed for calculation. The conversion operation must be considered and the return value is of the operand type. 2. *,/: multiply or divide the currency by a scalar value, which is set to double. However, the two currencies cannot be multiplied or divided. 3. = ,! =: Compare two currencies. different currencies are allowed for comparison, but the conversion operation must be considered. There are other operations that we will not consider for the moment. After all, the purpose here is not to develop a complete currency system. For the convenience of coding, four assignment versions are also defined here: + =,-=, * =,/=. To save space, only the +, *, and = codes are displayed. Other codes are also displayed: Template <int ty, int TP> inline bool operator = (currency <ty> & C1, const currency <TP> & C2) {return C1. _ Val = C2. _ Val * curr_rate [TP] [ty];} template <int ty, int TP> inline currency <ty> & operator + = (currency <ty> & C1, const currency <TP> & C2) {C1. _ Val + = C2. _ Val * curr_rate [TP] [ty]; return C1;} template <int ty, int TP> inline currency <ty> operator + (currency <ty> & C1, const currency <TP> & C2) {currency <ty> T (C1); t + = c2; return t;} note the currency conversion operations in the = and + operators, each time, the second operand currency is converted to the first operand currency before the operation. The type of the first parameter is different from that of the second parameter. Therefore, different currencies are allowed for calculation. This can further simplify the code and completely program in a logical way. Template <int ty> inline currency <ty> & operator * = (currency <ty> & C1, const double Q) {C1. _ Val * = Q; return C1 ;} template <int ty> inline currency <ty> operator * (currency <ty> & C1, const double Q) {currency <t, Ty> T (C1 ); T * = Q; return t;} template <int ty> inline currency <ty> & operator * = (const double Q, currency <ty> & C1) {return operator * = (C1, q);} template <int ty> inline currency <ty> operator * (const double Q, Cu Rrency <ty> & C1) {return operator * (C1, q );}... * Only one operator parameter is of the currency type, and the other is of the double type, indicating the number. It only makes sense to multiply the number of currencies, isn't it? * The operator includes two versions: one currency is in the front, the number is in the back, the other is in the front, and the other is in the back. In order to adapt to two different writing methods: RMB _ * 1.4 and 1.4 * RMB _, the algorithm is the same. Now the currency can be computed: USD _ = USD _ * 3; // UKP _ = RMB _ * 2.5 for the same currency; /// after calculation, the value is directly assigned to another currency jpd _ = UKP _ = RMB _ + USD _; // same as above, but four currencies are involved in the calculation, the currency operation is very convenient. You do not need to consider the currency type. The currency conversion is automatic without additional code. While simplifying the code, it also provides operational constraints, such as UKP _ = RMB _ * USD _; // compilation error. It doesn't make sense to multiply another currency !!! This code will cause a compilation error because we do not provide the * overload for the multiplication of the two currencies. Obviously, multiplication of one currency and another is meaningless. Here, we use the static overload type check to constrain the operation applied on the currency. The code that violates the logic is blocked immediately to avoid running errors. You must know that the mistake of assigning two currencies to another currency by multiplying the two currencies is very concealed and will only be found at the time of inventory or checkout. Good. Here we use some special mechanisms of the C ++ template, as well as operator templates, Operator overloading, and other technologies to develop a currency system. This system can use the simplest statement to calculate and convert various currencies. At the same time, the heavy load mechanism is also used to provide operational constraints that comply with the business logic. Currency calculation is only a simple case, but the related technologies can be further promoted to more complex fields. The more complex the business, the more benefits it receives. Therefore, fully understanding and using the generic programming functions brought about by C ++ can greatly simplify software development, reduce code errors, and reduce development costs. This technology is applicable to entities with the same features physically, but logically different. On the one hand, these entities are strongly typed in the code to obtain overload and type detection capabilities. Because the corresponding types of logical entities in the Code are strongly typed, we can use heavy load, static type detection and other technical means to achieve only the elements provided by the language, the ability to directly construct a business model in the code. However, it is laborious and trivial to manually type every logical entity, and there is a lot of repetitive work. At this point, we can use the abstract capabilities of the template, and in turn use the common physical characteristics of the logical entity to build an abstract template at one time, and use some features of template instantiation, it is convenient to construct a new type (only one typedef ).
This technology can be further expanded to provide more advanced applications. A classic example is to implement dimensional analysis during the compilation period. In the template meta-programming book, I will explain this in detail.