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

Use variadic function as template argument

我想让下面的代码在不改变 Child1Child2 class 的情况下工作:

#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 继承自已使用 triple 函数实例化的 Parent。因此,当 Child1 被实例化为 4 时,它输出“constructed: 12”。

相比之下,Child2被注释掉了,因为它显然还不能工作。在主函数中,我试图将两个参数传递给 Child2 构造函数,就像底层 add() 函数所期望的那样。然而,Parent 的构造函数只接受一个参数,可能需要在它前面加上 template<typename Args...> 来解决问题。此外,Parent class 将需要一个模板参数,如 int (*F)(Args...)。最终,像 main 函数那样构造一个 Child2 实例应该输出“constructed: 11”。

我怎样才能做到这一点,即创建一个模板参数,它是一个可以有任意数量参数的函数?再次请注意,Parent class 的代码是唯一可以更改的内容。

在 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

来不及玩了?

我提出了基于 auto 的 C++17 VTT 答案的变体,它使用 class 专业化来提取 Args... 输入类型(和 Ret 类型,如果有用的话)。

我是说

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};
 }

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