In c language, APIs are embodied as c functions, such as a series of Apis provided by the operating system. In c ++, APIs are embodied as free functions, free functions here refer to functions that can be directly accessed in a namespace scope or global space except common member functions, static member functions, and friend functions, this is more embodied in function templates, such as a series of algorithms provided by stl, among which the famous ones include swap, count, and sort. Compared with c API, c ++ API has the advantages of type security and closed opening. type security is because c ++ itself is a more powerful static type language than c, closed and open means that part of the function design and implementation is fixed, while the other part can be flexibly expanded, which is manifested in the heavy load and global special implementation of the function template. This article describes how to use a function template to design your own application APIs, and uses windows APIs as an example.
In windows, many APIs generally have ANSI and UNICODE character sets. Their names correspond to xxxA and xxxW. If the application layer needs to encapsulate its own APIs for these APIs, ANSI and UNICODE versions must be considered for completeness. There are two methods. One is to first implement A version A (or W), while the implementation of version W (or A) is to convert UNICODE (or ANSI) converts A type to an ANSI (or UNICODE) type, and then calls version A (or W). This method is less efficient because it needs to be converted into character sets; the second is the parallel implementation of the two versions, that is, Version A calls the api implementation of the original version windows A, and version W calls the api implementation of the original version windows W, the disadvantage of this method is that the results produce A lot of repeated Code except that A or w api calls are different. After both version A and version W are implemented, you can define an API macro Based on the macro definition _ UNICODE or UNICODE of the compiler. In addition to the above two methods, is there any better way to achieve this? This method must take into account the efficiency and avoid code duplication and redundancy. Here, we will describe a method to encapsulate the design using function templates. before using this method, there are several problems to solve: 1) how to define the correct struct based on generic parameters, because some windows API parameters not only have string types A and W, in addition, any struct containing the string type also contains the and W types. 2) how to choose to call the original windows API of the correct version based on generic parameters.
For windows API encapsulation, generic parameters are generally only A or W. Therefore, you can use the feature class template to solve the above 1st problems, such as if_c in boost, select_first_type class template in softstl, you can also implement this class template by yourself. For the above 2nd questions, what is different from the 1st questions is that it selects a function rather than a type, and essentially selects a variable, therefore, we need to develop an infrastructure that selects variables based on type or non-type parameters. How can this infrastructure be implemented? As a result, I expect this infrastructure to be used in this way: select_variable <flag> (xxxA, xxxW) (arg1, arg2 ,..., argN); flag is a real parameter of a Boolean non-type template. When its value is true, it indicates that the windows API xxxA is returned, and the windows API xxxW is returned, followed by a series of parameters, indicates that the corresponding windows API of Version A or version W is called. Therefore, select_variable should be implemented as A function template conveniently. If it is implemented as A class template (for implementation, refer to the function in boost ), you need to explicitly specify the function return value and parameter type. In this way, when there are too many function parameters, it is a nightmare because the real-time parameter deduction of the template cannot be used for class templates and Their constructors, it can only be applied to its member function templates. To solve these two problems, I have implemented a Feature Template and developed and maintained it as the basic library. The code is named select_trait. The Code is as follows:
1 # define TEMPLATE_BOOL_TRAIT_DEF1 (trait, T, c )\
2 template <typename T> \
3 struct trait \
4 {\
5 static const bool value = c ;\
6 };\
7
8 # define TEMPLATE_BOOL_TRAIT_SPEC1 (trait, sp, c )\
9 template <> \
10 struct trait <sp> \
11 {\
12 static const bool value = c ;\
13 };\
14
15 template <bool flag, typename T1, typename T2>
16 struct select_type;
17
18 template <typename T1, typename T2>
19 struct select_type <true, T1, T2>
20 {
21 typedef T1 type;
22 };
23
24 template <typename T1, typename T2>
25 struct select_type <false, T1, T2>
26 {
27 typedef T2 type;
28 };
29
30 template <bool flag, typename T1, typename T2>
31 inline typename select_type <flag, T1, T2>: type select_variable (T1 t1, T2 t2)
32 {
33 return select_variable_impl (typename select_type <flag, int, long >:: type (), t1, t2 );
34}
35
36 template <typename T1, typename T2>
37 inline T1 select_variable_impl (int, T1 t1, T2 t2)
38 {
39 return t1;
40}
41
42 template <typename T1, typename T2>
43 inline T2 select_variable_impl (long, T1 t1, T2 t2)
44 {
45 return t2;
46}
47
48TEMPLATE_BOOL_TRAIT_DEF1 (is_ansi_char, T, false)
49TEMPLATE_BOOL_TRAIT_SPEC1 (is_ansi_char, char, true)
50TEMPLATE_BOOL_TRAIT_SPEC1 (is_ansi_char, char const, true)
51TEMPLATE_BOOL_TRAIT_SPEC1 (is_ansi_char, char volatile, true)
52TEMPLATE_BOOL_TRAIT_SPEC1 (is_ansi_char, char const volatile, true)
53
54 # undef TEMPLATE_BOOL_TRAIT_DEF1
55 # undef TEMPLATE_BOOL_TRAIT_SPEC1
With this infrastructure select_trait Feature Template, it is much easier to encapsulate and design your own APIs. In the function template, type parameterization is reflected in its parameters, return values, and internal implementations, the following three examples illustrate the application:
(1) parameter type. For example, to determine whether the path is A directory or file, the caller can flexibly specify the string path of Version A or version W, as shown below: www.2cto.com
1 template <typename charT>
2 inline int IsDirectoryOrFile (const charT * path)
3 {
4 DWORD dwFlag = select_variable <is_ansi_char <charT >:: value> (GetFileAttributesA, GetFileAttributesW) (path );
5 if (INVALID_FILE_ATTRIBUTES = dwFlag)
6 return 0;
7 return (dwFlag & FILE_ATTRIBUTE_DIRECTORY )? 1: 2;
8}
(2) return value type. For example, the most common method to obtain the path of the current application, the caller can flexibly specify the path represented by A or W string to return, as shown below:
1 template <typename T>
2 inline std: basic_string <T> GetExePath ()
3 {
4 T szExePath [MAX_PATH];
5 select_variable <is_ansi_char <T>: value> (GetModuleFileNameA, GetModuleFileNameW) (NULL, szExePath );
6 return szExePath;
7}
(3) internal implementation typing, such as calculating the size of a directory or file. Because FirstFirstFile and FirstNextFile are used internally, these two APIs are not only paths, in addition, the WIN32_FIND_DATA structure has versions A and W. Therefore, you need to define the correct struct variables and call the correct API functions, as shown below:
1 template <typename charT>
2 inline ULONGLONG GetDirSize (const charT * path)
3 {
4 int ret = IsDirectoryOrFile (path );
5 if (0 = ret) return 0L;
6
7 std: basic_string <charT> strPath = path;
8 if (1 = ret)
9 {
10 if (strPath. length ()-1! = StrPath. rfind (charT )'\\'))
11 strPath + = (charT )'\\';
12 strPath + = select_variable <is_ansi_char <charT>: value> ("*. *", L "*.*");
13}
14 ULONGLONG ullSumSize = 0;
15 typename select_type <is_ansi_char <charT>: value, WIN32_FIND_DATAA, WIN32_FIND_DATAW >:: type findData;
16 HANDLE hFindFile = select_variable <is_ansi_char <charT >:: value> (FindFirstFileA, FindFirstFileW) (strPath. c_str (), & findData );
17
18 for (BOOL bResult = (hFindFile! = INVALID_HANDLE_VALUE );
19 bResult; bResult = select_variable <is_ansi_char <charT >:: value> (FindNextFileA, FindNextFileW) (hFindFile, & findData ))
20 {
21 if (findData. cFileName [0] = (charT )'.')
22 continue;
23 if (findData. dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
24 {
25 strPath = strPath. substr (0, strPath. rfind (charT) '\') + 1) + findData. cFileName;
26 ullSumSize + = GetDirSize (strPath. c_str (), bExitCalc );
27}
28 else
29 ullSumSize + = (ULONGLONG) findData. nFileSizeHigh) <32) + findData. nFileSizeLow;
30}
31: FindClose (hFindFile );
32 return ullSumSize;
33}
From Tiandao reward service