如何制作智能指针的可变参数函数?
How to make a variadic function of smart pointers?
我正在尝试使接口成为由派生子级实现的抽象类。该类中的方法之一必须是可变参数(根据实现,子项得到一个或多QSharedPointer<QObject>
)
问题是:
-
模板化方法不能是虚拟的
-
由于
error: expansion pattern ‘QSharedPointer<QObject>’ contains no argument packs.
,我无法通过QSharedPointer<QObject>... args
参数进行可变参数方法
更少的单词,更多的代码:
class BaseClass {
public:
virtual void foo(QSharedPointer<QObject>... args) = 0;
}
class ChildClassA : public BaseClass {
public:
void foo(QSharedPointer<QObject> arg1);
}
class ChildClassB : public BaseClass {
public:
void foo(QSharedPointer<QObject> arg1, QSharedPointer<QObject> arg2);
}
我想使用上面的类来做这样的事情:
template <class T = BaseClass>
class Controller<T>{
void callFoo(QSharedPointer<QObject>... args){
T* = new T();
T->foo(args);
}
}
如您所见,BaseClass 只是说:使用我的一个孩子作为泛型类型。
我如何使这些东西工作?在C++甚至可能吗?
由于(根据评论)您已经按 arity 分隔了子级,并且它们由Controller
类模板的单独实例化管理,因此尝试将它们全部强制到同一层次结构中是没有意义的——这只意味着解决方法和运行时开销。
相反,让我们将BaseClass
做成一个模板,并使用它的参数来生成foo
的签名。
namespace detail {
template <std::size_t, class T>
using expandHook = T;
}
template <std::size_t N, class = std::make_index_sequence<N>>
struct BaseClass;
template <std::size_t N, std::size_t... Idx>
struct BaseClass<N, std::index_sequence<Idx...>> {
virtual void foo(detail::expandHook<Idx, QSharedPointer<QObject>>... args) = 0;
};
detail::expandHook
是一种语法技巧,可以多次重复QSharedPointer<QObject>
类型,因为有Idx
es,由于std::index_sequence
的工作,0
N - 1
。
然后,子项从相应的BaseClass
继承:
struct Child : BaseClass<2> {
void foo(QSharedPointer<QObject>, QSharedPointer<QObject>) override;
};
奖励:如果您希望孩子支持多种BaseClass
专长,则可以从多个专业继承!
最后,控制器将通过适当的BaseClass
类型进行参数化,并且一切都点击进入。
在 Coliru 上直播(带有存根类型,main
的内容将是Controller
内的内容)。
如果您遵循公共函数应该是非虚拟函数而虚拟函数应该是私有的准则,那么您可以通过将基本函数转换为可变参数模板函数来解决此问题,该模板函数委托给std::vector
的虚拟私有函数。
这也具有所有解包都发生在一个位置并且派生类更易于实现的优点。
下面是一个示例(我已将QSharedPtr
替换为std::shared_ptr
并为QObject
添加了虚拟实现,以便可以在没有第 3 方内容的情况下编译该示例):
#include <memory>
#include <vector>
#include <iostream>
#include <cassert>
struct QObject { virtual void sayHi() const = 0; };
struct DerivedQObject1 : public QObject { void sayHi() const override { std::cout << "1n"; } };
struct DerivedQObject2 : public QObject { void sayHi() const override { std::cout << "2n"; } };
class BaseClass {
public:
template <class... Types>
void foo(std::shared_ptr<Types>... args)
{
std::vector<std::shared_ptr<QObject>> vector;
pushBack(vector, args...);
assert(!empty(vector));
doFoo(vector);
}
private:
virtual void doFoo(std::vector<std::shared_ptr<QObject>> const& args) = 0;
template<typename LastType>
static void pushBack(std::vector<std::shared_ptr<QObject>>& vector, LastType arg)
{
vector.push_back(arg);
};
template<typename FirstType, typename ...OtherTypes>
static void pushBack(std::vector<std::shared_ptr<QObject>>& vector, FirstType const& firstArg, OtherTypes... otherArgs)
{
vector.push_back(firstArg);
pushBack(vector, otherArgs...);
};
};
class ChildClassA : public BaseClass {
private:
void doFoo(std::vector<std::shared_ptr<QObject>> const& args) override;
};
void ChildClassA::doFoo(std::vector<std::shared_ptr<QObject>> const& args) {
for (auto const& arg : args) {
arg->sayHi();
}
}
int main() {
ChildClassA child;
auto obj1 = std::make_shared<DerivedQObject1>();
auto obj2 = std::make_shared<DerivedQObject2>();
child.foo(obj1, obj2);
}
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 如何使用可变参数模板强制转换每个变体类型
- 关于如何在具有单个参数的变体构造中选择替代方案?
- 调用参数排列不变函数 f(i++, i++)
- 参数归纳与标准::变体
- 模板化回调参数的逆变,如 C# 中的逆变
- 如何在没有参数包的情况下编写变差函数
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 获取模板参数的成员变量值列表
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- 如何定义变体<x,y,z>提取模板参数的子类型
- 正确对齐内存模板,参数顺序不变
- 递归中不同参数类型的变元模板函数
- 通过函数指针传递给变差函数的参数会更改其值
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 使用可变参数模板参数提升变体访问者
- boost ::变体 - 为什么模板参数比const字符串参数具有更高的优先级
- 将变参数包中的值加载到临时数组中
- 使用额外参数提升变体访客
- 从变长参数列表中提取std::string