在模板基类中为继承类中的可选重写生成虚拟方法
Generating virtual methods in template base class for optional override in inheriting class
我想要的是一个模板类,给定元组并用作基类,为元组中的每种元素类型提供具有默认行为的方法。这些方法应该是虚拟的,这样它们就可以在继承类中被重写。
下面的代码正是这样做的:
#include <tuple>
#include <iostream>
struct A {};
struct B {};
struct C {};
template <typename Class, uint16_t tag>
struct def {
using message_type = Class;
static constexpr uint16_t class_tag = tag;
};
// (3) adding "constexpr" or "const" causes compilation failure
auto t = std::make_tuple(def<A, 0>(), def<B, 1>(), def<C, 2>());
template <typename T> // (1)
struct base_handler_t {
virtual void h(T const& t) { std::cout << "base_handler_tn"; }
};
template <typename ...Ts> // (2) - adding "const" to "std::tuple<Ts...>" in line below makes code work again if "t" is constant
struct base_handler_t<std::tuple<Ts...>> : public base_handler_t<typename Ts::message_type>...{
using base_handler_t<typename Ts::message_type>::h...;
};
struct service_t : public base_handler_t<decltype(t)> {
using base_handler_t<decltype(t)>::h;
void h(B const & b) {
std::cout << "service_tn";
}
};
int main() {
service_t n;
n.h(A());
n.h(B());
}
在找到破坏代码的精确且最小的示例后进行编辑:
按原样输入时,上面的代码可以正常工作,但如果注释(3)
(关于将constexpr
添加到t
的定义(下面的行更改为:
const auto t = std::make_tuple(def<A, 0>(), def<B, 1>(), def<C, 2>());
或
constexpr auto t = std::make_tuple(def<A, 0>(), def<B, 1>(), def<C, 2>());
代码编译失败。编译器声称:
x.cc: In function ‘int main()’:
x.cc:35:16: error: no matching function for call to ‘service_t::h(A)’
35 | n.h(A());
| ^
x.cc:28:14: note: candidate: ‘void service_t::h(const B&)’
28 | void h(B const & b) {
| ^
x.cc:28:26: note: no known conversion for argument 1 from ‘A’ to ‘const B&’
28 | void h(B const & b) {
| ~~~~~~~~~~^
x.cc:18:22: note: candidate: ‘void base_handler_t<T>::h(const T&) [with T = const std::tuple<def<A, 0>, def<B, 1>, def<C, 2> >]’
18 | virtual void h(T const& t) { std::cout << "base_handler_tn"; }
| ^
x.cc:18:33: note: no known conversion for argument 1 from ‘A’ to ‘const std::tuple<def<A, 0>, def<B, 1>, def<C, 2> >&’
18 | virtual void h(T const& t) { std::cout << "base_handler_tn"; }
| ~~~~~~~~~^
我假设,当涉及到模板时,如果类型是从常量或变量中提取的,就没有真正的区别。
代码在以下行更改后开始工作(2(:
struct base_handler_t<std::tuple<Ts...>> : ...
至
struct base_handler_t<const std::tuple<Ts...>> : ...
为什么会这样?是因为std::tuple<Ts...>
与const std::tuple<Ts...>
不完全匹配吗?本案的具体规则是什么?
提前谢谢。
最初的求助请求:
在原始代码中,每种类型的方法(上例中的A、B和C(都是在"service_t"类中手工定义的。我试图像上面的例子一样解决这个问题。只要所有方法都存在,代码仍然可以正常工作。当我注释掉单个方法时,我收到一个错误,并没有匹配的方法可以调用,然后是可能匹配的列表。方法与参数std::tuple<def<....
等匹配——在我上面的代码片段中,似乎一切都很好(因此为每个元组元素类型生成一个方法(,但有的东西阻止了更大的代码库与模板(2(匹配,而是使用模板(1(。
我想听听任何为什么会失败的想法。提前谢谢。
使用
auto t = std::make_tuple(def<A, 0>(), def<B, 1>(), def<C, 2>());
decltype(t)
是std::tuple<def<A, 0>, def<B, 1>, def<C, 2>>
如果t
是const
限定的:const auto t = /*..*/
,则decltype(t)
是const std::tuple<def<A, 0>, def<B, 1>, def<C, 2>>
。
所以对于base_handler_t<decltype(t)>
,base_handler_t<const std::tuple<def<A, 0>, def<B, 1>, def<C, 2>>>
只匹配主模板定义,而不是您的专业化。
您可以使用base_handler_t<std::remove_const_t<decltype(t)>>
或base_handler_t<std::decay_t<decltype(t)>>
(删除引用,然后删除cv限定符(
- 如何强制从重写方法调用重写的方法基方法?
- 具有引用返回类型的重写方法上的协变返回类型无效
- 调用不是来自直系父亲的重写方法
- Qt/C++ - 从派生类调用重写方法
- 重写方法优先 C++
- 为什么重写方法并将 const 添加到参数类型有效
- 如何在向量上调用不同的重写方法
- 处理C++中基类的重写方法的异常
- C重写C++方法
- 如何自动更新重写方法的 *this 返回类型
- 在 c++ 中具有不同返回类型的重写方法
- 未调用继承的重写方法
- 只有当类重写方法时,在动态加载的共享库中实例化的类才会丢失XCode 4.3/4.4 typeinfo
- 在构造函数中使用重写方法的替代方法,Java
- 使用父类型时重写C++方法
- 多个线程中的重写方法
- 关于在强制转换为子类的超类时调用其重写方法
- 如何在所有派生类中调用重写方法
- 返回对"this"的取消引用的重写方法
- C++-从方法基类调用派生类中的重写方法