我知道我可以将元组的参数包扩展到基类的可变参数模板 像这样:
#include <tuple>
struct ComponentA {
int foo;
int bar;
ComponentA(std::tuple<int, int> && pack):
foo(std::get<0>(pack)),
bar(std::get<1>(pack))
{}
};
struct ComponentB {
ComponentB(std::tuple<> && pack)
{}
};
template<typename ... Bases>
struct CompositeClass: public Bases... {
template<typename ... Arguments>
CompositeClass(Arguments &&... arguments):
Bases(std::forward<Arguments>(arguments))...
{}
};
int main() {
CompositeClass<ComponentA, ComponentB> composite{
std::make_tuple(100, 100),
std::make_tuple()
};
}
但是,我发现语法繁琐。有没有办法完全避免元组?
修改
更像这样:
struct ComponentA {
int foo;
int bar;
ComponentA(int a, int b):
foo(a),
bar(b)
{}
};
struct ComponentB {
ComponentB()
{}
};
template<typename ... Bases>
struct CompositeClass: public Bases... {
template<typename ... ... Arguments>
CompositeClass(Arguments &&... ... arguments):
Bases(std::forward<Arguments>(arguments)...)...
{}
};
int main() {
CompositeClass<ComponentA, ComponentB> composite{100, 100};
}
两个参数都传递给ComponentA,none传递给ComponentB。
修改2
所以我有这样的事情:
template <int ...>
struct SequenceContainer {};
template <int, typename>
struct AppendIntToSequence;
template <int Value, int ... Sequence>
struct AppendIntToSequence<Value, SequenceContainer<Sequence...>> {
typedef SequenceContainer<Sequence..., Value> type;
};
template<int End>
struct MakeSequence:
AppendIntToSequence<End - 1, typename MakeSequence<End - 1>::type> {};
template<>
struct MakeSequence<0> {
typedef SequenceContainer<> type;
};
struct ComponentA {
static const int parameters = 2;
ComponentA(int && a, int && b) {
std::cout << a << b << std::endl;
}
};
struct ComponentB {
static const int parameters = 1;
ComponentB(const char * string) {
std::cout << string << std::endl;
}
};
template <typename Base>
struct TupleConstructor: Base {
template <typename ... Arguments, int ... Sequence>
TupleConstructor(std::tuple<Arguments...> &&, SequenceContainer<Sequence...> const &);
};
template <typename Base>
template <typename ... Arguments, int... Sequence>
TupleConstructor<Base>::TupleConstructor(std::tuple<Arguments...> && arguments, SequenceContainer<Sequence...> const &):
Base(std::forward<Arguments>(std::get<Sequence>(arguments))...)
{}
template <typename ... Components>
struct CompositeClass: public TupleConstructor<Components>... {
template <typename ... Arguments>
CompositeClass(Arguments &&... arguments):
TupleConstructor<Components>(
std::forward<Arguments>(arguments),
typename MakeSequence<std::tuple_size<Arguments>::value>::type{}
)...
{}
};
int main()
{
CompositeClass<ComponentA, ComponentB> composite{
std::tuple<int &&, int &&>(100,100),
std::tuple<const char *>("Hello World!")
};
但是,我无法弄清楚如何从CompositeClass
构造函数中删除这两个元组。怎么办呢?
答案 0 :(得分:2)
看来,如果你在整个地方洒下一些时间,你应该没问题!参数包并不特别特别:它们只是扩展为逗号分隔列表。也就是说,如果您将代码更改为下面的代码,那么您应该没问题:
template <typename... Bases>
struct CompositeClass: public Bases... {
template <typename... Arguments>
CompositeClass(Arguments&&... arguments):
Bases(std::forward<Arguments>(arguments))...
{}
};
除了在初始化列表前添加冒号外,我只删除了一些多余的&#34; ...&#34;。只要所有模板参数实际上是类类型并且只要它们恰好不同,这就可以正常工作。显然,不属于类的类型不能用作基础。如果你需要多次基本相同的类型,你需要间接地继承它们为什么一个辅助类型给它们一个数字。生成这些数字有点棘手,你最初几次这样做,但也没有真正神奇的。
扩展已编辑的问题:您的意思是,您希望将参数列表传递给每个基类构造函数?如果可以将std:tuple<...>
作为参数传递给CompositeClass
,那么这也是可行的。实质上,您需要将每个std::tuple<...>
转换为参数列表。这也需要产生所述指数。我至少会从一个辅助基础开始,它以std::tuple<...>
作为参数,并将成员作为参数转发给基础。这将使用与CompositeClass
上面的代码类似的东西,主要技巧将在辅助类中:
template <int... Numbers> struct Sequence {};
template <int N> struct MakeSequence;
template <typename Base>
struct AuxiliaryBase: Base {
template <typename Tuple, int... Numbers>
AuxiliaryBase(Tuple&&, Sequence<Numbers...> const&);
};
template <typename... Bases>
struct CompositeClass: public AuxiliaryBase<Bases>... {
template <typename... Args>
CompositeClass(Args&&... arguments):
AuxiliaryBase<Bases>(std::forward<Args>(arguments),
typename MakeSequence<std::tuple_size<Args>::size>())...
{}
};
实现AuxiliaryBase
的构造函数基本上要求有一个工具创建从0
到std::tuple_size<Tuple>::value
的整数序列。这需要一些调整,但绝对可行。为了使它们可用,传入一个辅助参数(我不确定是否可以避免这种情况;好吧,如果应该避免这种情况,可能它可以打包为std::tuple<...>
的类型)。有了这个,基类构造函数非常简单:
template <typename Base>
template <typename Tuple, int... Numbers>
AuxiliaryBase<Base>::AuxiliaryBase(Tuple&& tuple, Sequence<Numbers...> const&):
Base(std::get<Numbers>(tuple)...)
{}
我还没有对它进行测试,但这些方面的内容实际上应该可行。这个版本没有做的是完美转发std::tuple<...>
中的成员:为此你需要std::forward<>()
的变体,它需要三个参数,它们使用外部类型的参考资格来确定成员需要转发哪种参考。我没有试过这个,但它也可能是一个有趣的练习。
我还没有尝试编译这个特定的例子,但我过去确实做过类似的事情:如果你看slides我在ACCU会议上发表的演示文稿2010您将找到有关如何执行此操作的所有详细信息(包括如何创建一个整数序列;实际上非常简短。)