Re: [問題] 動態決定variadic 函數的參數個數

看板C_and_CPP作者 (高髮箍)時間11年前 (2013/07/24 23:29), 編輯推噓2(203)
留言5則, 4人參與, 最新討論串2/2 (看更多)
※ 引述《Wush978》之銘言: : 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...) : hiredis, C client of redis server : 問題(Question): : hiredis中提供了一個類似`printf`的API來傳送指令給redis server: : ex: : ```c : reply = redisCommand(context, "SET foo %s", value); : reply = redisCommand(context, "SET foo %s %s %s", value1, value2, value3); : ``` : 我希望後面接的參數是可以動態決定數量的。因此我想要把它包成一個繼承自 : `std::ostream`的class : 如此一來,要動態決定參數數量就變得很簡單: : ```cpp : Command << "SET foo " << value1 << value2 << value3; : ``` : 但是目前函式庫只有提供: : void *redisvCommand(redisContext *c, const char *format, va_list ap); : void *redisCommand(redisContext *c, const char *format, ...); : 不知道有沒有人有用C++處理variadic function的經驗。 : 有一種解法是自行寫出va_list的資料結構後直接餵給`redisvCommand`, : 但是這種寫法似乎不容易跨平台,所以我先不考慮。 : 請問有沒有人有更好的作法? 其實這不算動態決定, 因為傳進去的引數個數都寫死在程式 碼裡了. 我們需要一個函式 format(), 它可以回傳 redisCommand() 需要的格式字串, 格式字串怎麼產生呢? 由參數的型態而定. 也就是說遇到下列定義時: int value1; double value2; format(value1, value2); // 回傳 "%d %f" 1) 我們需要 template function 來得知引數型態 2) 我們需要函式接受任意個數引數. C++11 的 feature: Variadic template 就能達成這件事 -> http://ppt.cc/LFuE 一開始的框架類似長這樣: template <typename... Ts> std::string format(Ts&&... values); 在 format() 內部我們必須將 Ts 展開並且對逐個型別取得 對應的 specifier. 首先針對每一個型別, 設計專用的 meta-function: template <typename T> struct get_specifier; template <> struct get_specifier<int> { static constexpr char const* value = "%d"; }; ... 為了能順利地迭代每個引數, 我會將它們包裝成 tuple, 有 現成工具要取得特定位置的型別也很簡單. 創建 format() 的 helper class 如下: template <size_t Index, typename... Ts> struct format_runner<Index, std::tuple<Ts...>> { using tuple_type = std::tuple<Ts...>; template <typename String> static String execute(String&& init) { return format_runner< Index-1, tuple_type >::execute(std::forward<String>(init)) + " " + get_specifier< typename std::tuple_element< Index, tuple_type >::type >::value; } }; 用遞迴的方式展開, 記得寫一個 format_runner<0, ...> 來 終止具現化. 能傳型態就傳型態, 或用 std::forward() 以免 拖垮效能. 最後的實作長得像這樣: http://ideone.com/dLjgZY 當然 get_specifier<T> 你還可以再設計得好一點 -- ╔═══╗╔═══╗ ╔═╗═╗╔═══╗╔═══╗╔╦═╦╗ 金栽經║ ╔╗ ║║ ╔╗ ║╔╗║ ║ ║║ ═ ║║ ╔╗ ║║║ ║║RAINNOUS ≡≡║ ╚╝ ║║ ╚╝ ║║║║ ║║ ╞╣║ ║║ ║║ ║ ═╣║ ╥ ║║║║ ║ ║║ ═ ║║ ╚╝ ║║ ║ ║ 高佑麗╚═╩═╝╚═╩═╝╚╝╚═╚═╝╚═══╝╚═══╝╚═╩═╝鄭允慧 趙賢榮金智淑盧 乙吳勝雅ψmocki -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 112.105.158.161 ※ 編輯: loveme00835 來自: 112.105.158.161 (07/24 23:44) ※ 編輯: loveme00835 來自: 223.138.193.188 (07/25 09:15)

07/25 10:27, , 1F
07/25 10:27, 1F

07/25 16:45, , 2F
因為看懂的沒幾個,所以沒人推!(誤
07/25 16:45, 2F

07/25 22:20, , 3F
0rz... 真得很難嗎?
07/25 22:20, 3F

07/25 23:32, , 4F
謝謝。我之前有試過這招,但是沒有成功。等等來研究大大
07/25 23:32, 4F

07/25 23:32, , 5F
的寫法。
07/25 23:32, 5F
文章代碼(AID): #1Hx_B1Pa (C_and_CPP)
文章代碼(AID): #1Hx_B1Pa (C_and_CPP)