重载函数作为可变参数模板函数的参数

krd*_*dln 7 c++ variadic-functions variadic-templates c++11

我正在尝试创建可变参数模板函数,它将参数作为重载函数及其参数:)

int sumall(int a) { return a; }
int sumall(int a, int b) { return a+b; }

template<typename R, typename... A>
R doit( R(*f)(A...), A... a) {
    return f(a...); }
Run Code Online (Sandbox Code Playgroud)

我想调用doit没有任何模板说明符或转换:

cout << doit(sumall, 7, 6) << endl
Run Code Online (Sandbox Code Playgroud)

这不会编译,但当返回类型无效时,一切都很完美:

void printsum(int a) { cout << a << endl; }
void printsum(int a, int b) { cout << a+b << endl; }

template<typename... A>
void vdoit( void(*f)(A...), A... a) {
    f(a...); }

// ...
vdoit(printsum, 7, 6);
Run Code Online (Sandbox Code Playgroud)

是否可以修改第一个模板以使用仅限modyfing doit模板(我想保留sumall函数和doit调用)?我认为可以通过删除typename R和离开来完成,template<typename... A>因为R依赖A...f,但我不知道如何显示依赖.

Die*_*ühl 7

在获取函数的指针时,编译器需要知道您要使用哪个重载.没有办法将指针传递给"重载集"并让编译器稍后决定.你们两个例子都不适用于我尝试的任何编译器(最新版本的EDG,gcc和clang).

我不认为你可以做你想做的事而不改变你的电话记号.如果您愿意更改调用,可以将有关要调用的函数的知识封装到类中,例如:

struct sumall_t {
    template <typename... T>
    auto operator()(T... args) -> decltype(sumall(args...)) {
        return sumall(args...);
    }
};
Run Code Online (Sandbox Code Playgroud)

这有效地为过载集创建了一个包装器.由于结果类型不能直接推导出来并且可能取决于函数的调用方式,因此您还需要使用不同的版本doit():

template<typename Func, typename... A>
auto doit( Func f, A... a) ->decltype(f(a...)) {
    return f(a...);
}
Run Code Online (Sandbox Code Playgroud)

然后使用这样的东西:

doit(sumall_t(), 1, 2);
Run Code Online (Sandbox Code Playgroud)

修复此问题的另一种方法是强制要求结果类型的规范:在某种程度上,您尝试同时执行两项操作:您希望推导出要调用的函数的结果类型,并且您希望引导编译器选择特定的结果集的重载.但是,这些是相互依存的.如果从函数指针中删除对推导任何模板的任何依赖性,则不需要包装重载集,因为您可以确定从第一个参数到函数的重载函数的选择.如果您声称"如果返回类型不是我的编译器可以执行此操作void",我会说您的编译器在执行此操作时实际上是错误的.