我正在尝试创建一个函数模板,它将接受下面列出的两个(或更多)嵌套的可变参数类模板作为参数,并将它们放入另一个将接受不同类型的数据结构中(对或元组是什么我很可能会使用)。以下是类和子类,以及我的函数的用法(函数在下面进一步定义):
template<typename... Args> struct Entity {
template<typename... InnerEntArgs> struct InnerEntity {
InnerEntity(InnerEntArgs... inner_ent_args) {
... //do stuff w/ InnerEntArgs pack
... //do stuff that makes Inner dependent on Outer's Args pack
}
};
};
struct ThingA : Entity<int, string> {
... //construct ThingA
};
struct ThingB : Entity<string, string> {
... //construct ThingB
};
auto foo = my_func(
ThingA::InnerEntity<int, int, int>(1, 2, 3)
, ThingB::InnerEntity<string, int>("bar", 1)
);
下面是我为该函数拼凑的代码,它编译得很好,但我不确定它是否设置正确。具体来说,我对typename
和::template
如何使编译器在此上下文中感到满意,或者如果此函数的行为方式符合我的期望,我有点模糊:
template<
typename... ArgsA, typename... ArgsAInner
, typename... ArgsB, typename... ArgsBInner
> auto my_func(
typename Entity<ArgsA...>::template InnerEntity<ArgsAInner...> A
, typename Entity<ArgsB...>::template InnerEntity<ArgsBInner...> B
) -> tuple<decltype(A), decltype(B)> {
return make_tuple(A, B);
}
我认为我很清楚如何推断/推断参数包,以及auto
,decltype
和尾随返回类型如何进行但是,如果我弄错了,请告诉我如何。
另外,如果有人想要证明这个函数的可变版本可以接受任意数量的嵌套可变参数类模板并将它们放入合适的容器或数据结构中,那就太好了,但我主要关注的是完全理解typename
和::template
。提前谢谢!
*如果我错误地说了这个标题,或者我正在混淆条款,请解释一下。 :)我在这里学习。
答案 0 :(得分:4)
这不起作用,因为Entity<Args>::InnerEntity
是非推断的上下文。表示无法推断出ArgsA...
和ArgsAInner...
,同样适用于其他参数。这是因为在编译器可以推导出Args
之前,它必须知道InnerEntity
是哪个类型的成员,但要知道那个,它必须推导出Args
}。
您可以将此功能作为好友功能模板放入Entity<Args...>
并使其工作,只要两者都是同一模板的成员即可。但是上次我检查时,GCC没有找到类模板中定义的友元函数。
template<typename ...Args>
class Entity {
template<typename ...ArgsInner>
class InnerEntity {
};
template<typename ...ArgsAInner, typename... ArgsBInner>
> friend auto my_func(
InnerEntity<ArgsAInner...> A
, InnerEntity<ArgsBInner...> B
) -> tuple<decltype(A), decltype(B)> {
return make_tuple(A, B);
}
};
您还可以在InnerEntity
中声明一些指定外部类类型的成员typedef,并根据该类型制定my_func
,以便SFINAE可以为非成员进行排序。
template<typename ...Args>
class Entity {
template<typename ...ArgsInner>
class InnerEntity {
typedef Entity outer_entity;
};
};
template<typename A, typename B, typename Result>
struct require_entity { };
template<typename ...ArgsA, typename ...ArgsB, typename Result>
struct require_entity<Entity<ArgsA...>, Entity<ArgsB...>> {
typedef Result type;
};
template<template<typename...> class AInner, template<typename...> class BInner,
typename ...ArgsAInner, typename ...ArgsBInner>
> auto my_func(
AInner<ArgsAInner...> A
, BInner<ArgsBInner...> B
) -> typename require_entity<
typename AInner<ArgsAInner...>::outer_entity,
typename BInner<ArgsBInner...>::outer_entity,
tuple<decltype(A), decltype(B)>>::type
{
return make_tuple(A, B);
}
当然,如果您不需要访问template<typename...> class AInner
类型,则不需要ArgsAInner
这样的内容,例如上面的my_func
。在这种情况下,你最好只接受typename AInner
并且写得更少。 SFINAE仍将确保只接受正确的事情。