我想使以下代码完全不更改Child1
和Child2
类:
#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
类的代码是唯一可以更改的东西。
答案 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;
}
};
答案 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};
}
松散的完美转发,但可以控制参数的数量(和类型)。