接受嵌套可变参数类模板作为函数模板的参数

发布于 2024-09-24 16:44:46 字数 1591 浏览 4 评论 0原文

我正在尝试创建一个函数模板,它将接受下面列出的两个(或更多)嵌套可变参数类模板作为参数,并将它们放入另一个将接受不同类型的数据结构中(我将使用对或元组)最有可能使用)。以下是类和子类,以及我的函数的用法(该函数在下面进一步定义):

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);
}

认为我很好地掌握了如何推导/推断参数包,以及如何autodecltype和尾随返回类型正在做他们的事情,但如果我错了,请告诉我如何做。

另外,如果有人愿意演示此函数的可变参数版本,它可以接受任意数量的嵌套可变参数类模板并将它们放入合适的容器或数据结构中,那就太好了,但我主要关心的是完全理解typename::template。提前致谢!

*如果我对这个标题的措辞不正确或者我混淆了术语,请解释。 :) 我是来学习的。

I'm trying to make a function template that will accept two (or more) of the nested variadic class templates listed below, as arguments, and put them into another data structure that will accept different types (pair or tuple is what I'll most likely use). Here are the classes and subclasses, along with the usage of my function (the function is defined farther below):

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)
);

Below is the code I cobbled together for the function, and it does compile fine, but I'm not sure if it is set up correctly. Specifically, I'm a little fuzzy on how typename and ::template are making the compiler happy in this context, or if this function will behave the way I'm expecting:

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);
}

I think I have a good grasp on how the parameter packs are being deduced/inferred, and how auto, decltype, and the trailing return type are doing their thing, but if I'm mistaken, please let me know how.

Also, if anyone cares to demonstrate a variadic version of this function that can accept any number of the nested variadic class templates and put them into a suitable container or data structure, that'd be great, but I'm primarily concerned with fully understanding typename and ::template. Thanks ahead of time!

*If I've worded this title incorrectly or I'm mixing up terms, please explain. :) I'm here to learn.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽清梦 2024-10-01 16:44:46

这将不起作用,因为 Entity::InnerEntity 是非推导上下文。意味着无法推导出 ArgsA...ArgsAInner...,对于其他参数也是如此。这是因为,在编译器推导出 Args 之前,它必须知道 InnerEntity 属于什么类型,但要知道那个,它有推导Args

您可以将此函数作为友元函数模板放入 Entity 中,并使其工作(只要两者都是同一模板的成员)。但上次我检查时,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。 class AInner 事物,如果您不需要访问 ArgsAInner 类型,如上面的 my_func 所示。在这种情况下,您最好只接受 typename AInner 并且编写更少的内容。 SFINAE 仍将确保只接受正确的内容。

This will not work because Entity<Args>::InnerEntity is a non-deduced context. Means that ArgsA... and ArgsAInner... cannot be deduced, likewise for the other parameter. This is because before the compiler can deduce Args, it has to know what type InnerEntity is a member of, but to know that, it has to deduce Args.

You can put this function as a friend function template into Entity<Args...> and make it work as long as both are members of the same template. But last time I checked, GCC did not find friend functions defined in class templates.

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);
  }

};

You could also declare some member typedef in InnerEntity that specifies the type of the outer class, and formulate my_func in terms of that, so that SFINAE can sort it out for non-members.

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);
}

Of course you don't need that template<typename...> class AInner thing if you don't need to access the ArgsAInner types, like in the above my_func. In such a case you are better off just accepting typename AInner and have less to write. The SFINAE will still make sure only the right thing is accepted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文