【发布时间】:2021-07-07 00:42:11
【问题描述】:
在模板类中,我们可以检查成员函数的签名并为不同的子类定义不同的编译行为吗?更具体地说,请考虑以下简单示例:
template <typename T>
class Foo {
// ingore all other functions
virtual std::shared_ptr<T> do_something(int a) {
return std::make_shared<T>(a);
}
};
这应该适用于 T1 类:
class T1 {
T1(int a) {
// implememntation
}
// ingore all other functions
};
// Foo<T1> would just work
但是,使用T2 会导致编译失败,因为Foo 的do_something 函数被明确实现为仅使用一个参数调用T 的构造函数:
class T2 {
T2(int a, int b) {
// implememntation
}
// ingore all other functions
};
// Foo<T2> would fail to compile
所以问题是,我们能否对Foo 进行重新设计,让它同时适用于T1 和T2,就像T1 和构造函数采用int 参数的类一样,它将使用默认实现进行编译,而对于T2 和构造函数不同的类,它将使用虚函数编译并强制子类使用override 实现它。有点像下面:
Template <typename T>
class Foo {
// ingore all other functions
/* if T's signature takes one int input only
* compile like the below
*/
virtual std::shared_ptr<T> do_something(int x) {
return std::make_shared<T>(x);
}
/* if T's signature is different
* compile like the below and let the subclass implement it
*/
virtual std::shared_ptr<T> do_something(int x) = 0;
}
这是否可能不使用任何 3rd-party 库?如果我们必须使用宏/预处理器,这是可以接受的。
如果必须有一个函数do_something 也是可以接受的,但是对于签名不匹配的情况,它只会引发运行时异常,例如:
Template <typename T>
class Foo {
// ingore all other functions
virtual std::shared_ptr<T> do_something(int x) {
/* if T's signature takes one int input only
* compile like the below
*/
// return std::make_shared<T>(x);
/* if T's signature is different
* compile like the below and let the subclass implement it
*/
// std::throws...
}
}
【问题讨论】:
-
do_something是虚拟的有特定原因吗? -
是的,因为子类可能希望在应用程序中覆盖它;和
Foo的其他函数可能也需要调用覆盖的do_something。 -
在 C++ 中不可能有两个具有相同签名的类方法,SFINAE 也无济于事。
Foo本身有可能从基于T的专门化类继承,其专门化将实现适当的do_something替代方案。这将是一堆代码,但这是可能的,并且对于每个do_something重载都需要做同样的事情。这是这里能做的最多的事情。 -
为什么不简单地将
Foo::do_something()设为可变参数模板,以便它可以接受任意数量的构造函数参数? -
因为它必须是虚拟的,见上文。