本文將使用 泛型 實現可變參數。 涉及到的關見函數: std::snprintf
1、一個例子
函數聲明及定義
1 // 泛型 2 template <typename... Args> 3 std::string show_str(const char *pformat, Args... args) 4 { 5 // 計算字符串長度 6 int len_str = std::snprintf(nullptr, 0, pformat, args...); 7 8 if (0 >= len_str) 9 return std::string(""); 10 11 len_str++; 12 char *pstr_out = nullptr; 13 pstr_out = new(std::nothrow) char[len_str]; 14 // 申請失敗 15 if (NULL == pstr_out || nullptr == pstr_out) 16 return std::string(""); 17 18 // 構造字符串 19 std::snprintf(pstr_out, len_str, pformat, args...); 20 21 // 保存構造結果 22 std::string str(pstr_out); 23 24 // 釋放空間 25 delete pstr_out; 26 pstr_out = nullptr; 27 28 return str; 29 }
2、一個調用例子
1 std::cout << "str = " << show_str("1-%s, 2-%.2f, 3-%d", "ABC", 12.3456, 100).c_str() << "\n";
3、輸出結果
演示環境為: VS2015 up3
4、完整代碼
1 #include <iostream> 2 3 // 泛型 4 template <typename... Args> 5 std::string show_str(const char *pformat, Args... args) 6 { 7 // 計算字符串長度 8 int len_str = std::snprintf(nullptr, 0, pformat, args...); 9 10 if (0 >= len_str) 11 return std::string(""); 12 13 len_str++; 14 char *pstr_out = nullptr; 15 pstr_out = new(std::nothrow) char[len_str]; 16 // 申請失敗 17 if (NULL == pstr_out || nullptr == pstr_out) 18 return std::string(""); 19 20 // 構造字符串 21 std::snprintf(pstr_out, len_str, pformat, args...); 22 23 // 保存構造結果 24 std::string str(pstr_out); 25 26 // 釋放空間 27 delete pstr_out; 28 pstr_out = nullptr; 29 30 return str; 31 } 32 33 // 入口函數 34 int main(int argc, char *argv[]) 35 { 36 std::cout << "str = " << show_str("1-%s, 2-%.2f, 3-%d", "ABC", 12.3456, 100).c_str() << "\n"; 37 38 system("pause"); 39 return 0; 40 }
5、總結
A、 new 和 delete 需要配對使用
B、可自定義日志輸出格式 和 構造c++格式化字符串。 更加方便輸出日志.
6、擴展 (c++11)
A、可變參數模板函數
C++11的新特性--可變模版參數是C++11新增的特性之一,它對參數進行了高度泛化,能表示0到任意個數
一個例子,其定義如下
1 // 可變參數模板函數 2 template <typename ... Args> 3 void vp_func(Args ... args) 4 { 5 // 計算參數個數 6 int count_param = sizeof...(args); 7 std::cout << "參數個數=" << count_param << std::endl; 8 }
其中,計算參數個數的方式:
int count_param = sizeof...(args);
B、調用
1 // 入口函數 2 int main(int argc, char *argv[]) 3 { 4 vp_func(1); 5 vp_func("-=+", 1.23456f); 6 vp_func(1, 2.2f, "ABC"); 7 8 system("pause"); 9 return 0; 10 }
C、輸出結果:
演示環境: VS2015 up3
D、解包(包展開)
有兩種方式
1)、遞歸
2)、非遞歸
遞歸,好用,但是要考慮爆棧的情況,不推薦。這里就不介紹了。
下面介紹非遞歸的方式展開
2.1)、定義展開函數
1 // 參數包展開 2 template<typename T> 3 void expand(const T t) 4 { 5 std::cout << t << std::endl; 6 }
再調用展開函數
1 // 可變參數模板函數 2 template <typename ... Args> 3 void vp_func(Args ... args) 4 { 5 // 計算參數個數 6 // int count_param = sizeof...(args); 7 // std::cout << "參數個數=" << count_param << std::endl; 8 9 std::initializer_list<int>{(expand(args), 0)...}; 10 // std::initializer_list<int>{([&] {std::cout << args << std::endl; }(), 0)...}; 11 }
2.2)、使用lambda 展開
1 // 可變參數模板函數 2 template <typename ... Args> 3 void vp_func(Args ... args) 4 { 5 // 計算參數個數 6 // int count_param = sizeof...(args); 7 // std::cout << "參數個數=" << count_param << std::endl; 8 9 // std::initializer_list<int>{(expand(args), 0)...}; 10 std::initializer_list<int>{([&] {std::cout << args << std::endl; }(), 0)...}; 11 }
非lambda 完整展開代碼:
1 // 參數包展開 2 template<typename T> 3 void expand(const T t) 4 { 5 std::cout << t << std::endl; 6 } 7 8 9 // 可變參數模板函數 10 template <typename ... Args> 11 void vp_func(Args ... args) 12 { 13 // 計算參數個數 14 // int count_param = sizeof...(args); 15 // std::cout << "參數個數=" << count_param << std::endl; 16 17 std::initializer_list<int>{(expand(args), 0)...}; 18 // std::initializer_list<int>{([&] {std::cout << args << std::endl; }(), 0)...}; 19 }