使用可变参数函数作为模板参数

时间:2018-10-20 19:25:23

标签: c++ templates variadic-templates variadic-functions

我想使以下代码完全不更改Child1Child2类:

#include <iostream>

int triple(int a) {
    return a * 3;
}

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

template<int (*F)(int)>
class Parent {
    public:
        Parent(int a) {
            std::cout << "constructed: " << F(a) << std::endl;
        }
};

class Child1 : Parent<triple> {
    public:
        Child1(int a) : Parent(a) {}
};

/*class Child2 : Parent<add> {
    public:
        Child2(int a, int b) : Parent(a, b) {}
};*/

int main() {
    Child1 child(4);
    //Child2 child(5, 6);
    return 0;
}

例如,您可以看到Child1继承自Parent函数实例化的triple。因此,当Child1用4实例化时,它输出“ constructed: 12”。

相反,Child2已被注释掉,因为它显然还不起作用。在主函数中,我试图将两个参数传递给Child2构造函数,就像基础add()函数期望它那样。但是,Parent的构造函数只接受一个参数,可能需要在其前面加上template<typename Args...>来解决。此外,Parent类将需要一个模板参数,例如int (*F)(Args...)。最终,像main函数一样构造一个Child2实例将输出“ constructed: 11”。

我该如何做到这一点,即创建一个模板参数,它是一个可以具有任意数量参数的函数?同样,请注意,Parent类的代码是唯一可以更改的东西。

2 个答案:

答案 0 :(得分:5)

对于C ++ 17,您可以使用推导的非类型模板参数并使构造函数成为可变参数模板:

template<auto x_pointer_to_function>
class Parent
{
    public:
    template<typename... x_Args>
    Parent(x_Args &&... args)
    {
        std::cout << "constructed: " << ((*x_pointer_to_function)(::std::forward<x_Args>(args)...)) << std::endl;
    }
};

online compiler

答案 1 :(得分:4)

玩太晚了吗?

我提出了一个基于auto的C ++ 17 VTT答案的变体,该答案使用类专门化来提取Args...输入类型(和Ret类型,如果有用的话)。 / p>

我的意思是

template <auto>
class Parent;

template <typename Ret, typename ... Args, Ret(*F)(Args...)>
class Parent<F>
 {
   public:
      Parent (Args const & ... as)
       { std::cout << "constructed: " << F(as...) << std::endl; }
 };

以下是完整的编译示例

#include <iostream>

int triple (int a)
 { return a * 3; }

long add (int a, int b)
 { return a + b; }

template <auto>
class Parent;

template <typename Ret, typename ... Args, Ret(*F)(Args...)>
class Parent<F>
 {
   public:
      Parent (Args const & ... as)
       { std::cout << "constructed: " << F(as...) << std::endl; }
 };

class Child1 : public Parent<triple>
 {
    public:
        Child1 (int a) : Parent{a}
         { }
 };

class Child2 : public Parent<add>
 {
    public:
        Child2 (int a, int b) : Parent{a, b}
         { }
 };

int main()
 {
   Child1 c1{4};
   Child2 c2{5, 6};
 }

松散的完美转发,但可以控制参数的数量(和类型)。