【问题标题】:Accepting nested variadic class templates as arguments to function template接受嵌套的可变参数类模板作为函数模板的参数
【发布时间】:2011-04-15 22:35:48
【问题描述】:

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

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。提前谢谢!

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

【问题讨论】:

    标签: c++ templates function c++11 variadic


    【解决方案1】:

    这将不起作用,因为Entity&lt;Args&gt;::InnerEntity 是非推断上下文。意味着不能推导出ArgsA...ArgsAInner...,对于其他参数也是如此。这是因为在编译器可以推断出Args 之前,它必须知道InnerEntity 是什么类型的成员,但是要知道那个,它必须推断出Args

    您可以将此函数作为友元函数模板放入Entity&lt;Args...&gt; 并使其工作,只要两者都是同一模板的成员。但是上次我检查时,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);
    }
    

    当然,如果您不需要访问ArgsAInner 类型,就像上面的my_func 一样,您不需要template&lt;typename...&gt; class AInner 的东西。在这种情况下,您最好只接受typename AInner 并少写一些东西。 SFINAE 仍将确保只接受正确的内容。

    【讨论】:

    • 我明白了。也许我在这里留下了相关信息,我仍然对上述为什么不起作用感到有些困惑。 Entity 有一些定义 Args 的子类,它有一个用于创建 InnerEntity 对象的成员函数,该成员函数接受并传递 InnerEntity 的 args 作为一个包。鉴于此,编译器是否应该能够推断出各种 Args 包,因为它们在编译时都是已知的?
    • @pheadbaq Entity 可以专门用于某些参数,例如 InnerEntity 与其他参数完全不同。一般来说,对于函数模板函数参数,如果你有typename T::foo,那么T不能被那个参数推导出来。
    • 在仔细研究了您的答案和我自己的代码之后,我认为朋友解决方案毕竟不会起作用,因为 ThingA 和 ThingB(请参阅我编辑的代码)不会继承自同一个实体模板。看起来类型名称 AInner + SFINAE 可以正常工作。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-11-22
    • 2011-08-26
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多