2011-11-13 75 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