2011-11-13 74 views
4

假設您想要編寫一個函數,該函數將一個不透明句柄傳遞給一個未知類型的函數(比如說,一個包含函數的結構體的名稱與商定名稱),並將參數轉發給該函數。C++ 11:計算可變參數函數參數

在非可變參數情況下,爲了簡單考慮單參數函數,有兩種方法可以做到這一點:可以讓轉發函數接受任意類型的參數,並嘗試用它調用forwardee函數,以及如果模板擴展不兼容,編譯器會在模板擴展期間發出抱怨;或者你可以使用decltype和各種其他機制來找出forwardee函數期望的參數類型,並明確地需要這種類型的參數。我不知道這些是否有任何可接受的術語,所以我會稱它們爲「通過」和「預先」。

通過方法直接推廣到具有任意數量的參數的函數,但前面的方法沒有。

#include <iostream> 

template<typename T, typename Arg> 
void pass_through_1(Arg arg) 
{ 
    T::f(arg); 
} 

template<typename T> struct arg_of_1; 

template<typename Ret, typename Arg> 
struct arg_of_1<Ret (Arg)> 
{ 
    typedef Arg type; 
}; 

template<typename T> 
void up_front_1(typename arg_of_1<decltype(T::f)>::type arg) 
{ 
    T::f(arg); 
} 

template<typename T, typename... Args> 
void pass_through_var(Args... args) 
{ 
    T::f(args...); 
} 

template<typename T> struct args_of_var; 

template<typename...> struct type_list; 

template<typename Ret, typename... Args> 
struct args_of_var<Ret (Args...)> 
{ 
    // typedef Args... type; // can't do this 
    typedef type_list<Args...> type; 
}; 

// template<typename T> 
// void up_front_var(typename args_of_var<decltype(T::f)>::type... args) // can't do this 
// { 
//  T::f(args...); 
// } 

struct test 
{ 
    static void f(int x) { std::cout << x*9 << std::endl; } 
}; 

int main(int, char**) 
{ 
    pass_through_1<test>(7); 
    up_front_1<test>(8); 
    pass_through_var<test>(9); 
    // up_front_var<test>(10); 
    return 0; 
} 

的問題是,參數包不準是自由站立,只能作爲模板參數,如果你在一個封閉的模板包裝他們,有沒有辦法解開,和解壓它們到位,只能通過模式匹配。

「前端」有一些優點,如更好的自我記錄和更好的類型推斷支持(up_front <T>本身可以被降級)。有什麼方法可以使它在可變情況下工作? (你當然可以使用std :: tuple,但這是相當令人滿意的。)

+2

缺點「先行」:無法處理重載函數或默認參數。 – aschepler

+0

好點。取決於用例。 – glaebhoerl

回答

1

沒有什麼比寫下問題讓你意識到答案。

這裏有一種方法:

template<typename T, typename Args = typename args_of_var<decltype(T::f)>::type> 
struct up_front_var; 

template<typename T, typename... Args> 
struct up_front_var<T, type_list<Args...>> 
{ 
    static void forward(Args... args) 
    { 
     T::f(args...); 
    } 
}; 

我不認爲有一種方式讓出來的這一個頂級功能(你遇到原來的問題再次),但是這可能不是太糟糕。

很高興看到其他解決方案。

0

也許我沒有正確理解這個問題,但是你總是可以省略參數類型並讓編譯器推斷它們。

/* declare */ 
template<typename T, typename... Args> 
void up_front_var(Args... args) 
{ 
    T::f(std::forward<Args>(args)...); // need std::forward to correctly handle lvalue/rvalue references 
} 

/* an example */ 
class Test { 
public: 
    static void f(const char* fmt, int a, int b); 
}; 

void Test::f(const char* fmt, int a, int b) 
{ 
    printf(fmt, a, b); 
} 


int main() 
{ 
    up_front_var<Test>("testing %u, %u", 1, 2); // no need to specify arguments here 
    return 0; 
} 
+0

是的,這是「傳遞」方法,幾乎​​逐字地提問(模std :: forward)。 – glaebhoerl