提问人:toxic 提问时间:5/25/2023 更新时间:5/25/2023 访问量:97
如何模拟“虚拟可变参数函数”部分的覆盖?
How to emulate override of parts of "virtual variadic functions"?
问:
首先,我知道可变参数函数在 c++ 中不能是虚拟的。我的问题是如何模仿下一个“不正确”的例子。我想要一个具有“虚拟可变参数函数”的类 A,以及继承它并仅实现“其中的一部分”的类 B:
class A {
template<class... Types>
virtual void f(Types... buffers) { return; }
};
class B : public A {
// Overrides only 2 options of "generic" f
void f(unsigned char* buff2) override;
void f(unsigned char* buff1, unsigned int* buff2) override;
};
在我的用例中,拥有这个泛型调用非常重要,但不同的类只支持可变参数函数的“子集”:f
f
A* a= factory(...);
a->f(buff1, buff2, buff3); // OK
a->f(buff1); // OK
a->f(buff1, buff2); // Error! Factory gave an instance which does not support this call
答:
0赞
Caleth
5/25/2023
#1
听起来你正在寻找.std::any
class A {
public:
template<class... Types>
void f(Types... buffers) { return f_impl(std::tuple(buffers...)); }
private:
virtual void f_impl(std::any arg) = 0;
};
class B : public A {
// Overrides only 2 options of "generic" f
void f_impl(std::any arg) override
{
if (auto * tup = std::any_cast<std::tuple<unsigned char*>>(&arg)) {
// single arg case
} else if (auto * tup = std::any_cast<std::tuple<unsigned char*, unsigned char*>>(&arg)) {
// two arg case
} else {
throw std::runtime_error("unsupported call"); // or whatever
}
};
但是,您的要求意味着一个可怕的设计问题。如果不知道它到底是什么子类,就不知道他们能用它做什么,这时他们应该引用该类型。A
2赞
Jarod42
5/25/2023
#2
您可以使用和使用重载作为调度,而不是虚拟:std::variant
class A {};
class B : public A {};
template<class... Types>
void f(A&, Types... buffers) { std::cout << "A" << sizeof...(buffers) << std::endl; }
void f(B&, unsigned char* buff1) { std::cout << "B1\n"; }
void f(B&, unsigned char* buff1, unsigned int* buff2) { std::cout << "B2\n"; }
然后
std::variant<A, B> vars[] = {A{}, B{}};
unsigned char buff1[42]{};
unsigned int buff2[42]{};
for (auto& var : vars) {
std::visit([&](auto& a_or_b) { f(a_or_b, buff1); }, var);
std::visit([&](auto& a_or_b) { f(a_or_b, buff1, buff2); }, var);
std::visit([](auto& a_or_b) { f(a_or_b); }, var);
}
1赞
Quentin
5/25/2023
#3
由于各种函数除了它们的名称之外实际上没有任何共享,因此我将它们建模为实际的独立接口,这与现有的 OOP 工具更好地啮合,这些工具可以处理有选择地实现接口的对象(即 )。 然后,它自己的模板只是隐藏了交叉转换和错误处理。f
dynamic_cast
A
f
template <class... Types>
struct HasF {
virtual void f(Types... buffers) = 0;
};
struct A {
virtual ~A() = default;
template <class... Types>
void f(Types... buffers) {
auto *const p = dynamic_cast<HasF<Types...>*>(this);
if(!p) {
// Error: the dynamic type cannot handle these arguments.
}
p->f(buffers...);
}
};
struct B
: A
, HasF<unsigned char *>
, HasF<unsigned char *, unsigned int *> {
void f(unsigned char* buff2) override { /* ... */ }
void f(unsigned char* buff1, unsigned int* buff2) override { /* ... */ }
};
下一个:为什么模板只能在头文件中实现?
评论
a
a