代码之家  ›  专栏  ›  技术社区  ›  Brett Rossier

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

  •  1
  • Brett Rossier  · 技术社区  · 14 年前

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

    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 ,后面的返回类型正在做它们的事情,但是如果我弄错了,请告诉我怎么做。

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

    *如果我用词不正确,或者我混淆了术语,请解释。:)我是来学习的。

    1 回复  |  直到 13 年前
        1
  •  4
  •   Johannes Schaub - litb    14 年前

    这不起作用,因为 Entity<Args>::InnerEntity 是非推断上下文。意思是说 ArgsA... ArgsAInner... 无法推导,其他参数也是如此。这是因为在编译器能够 Args ,它必须知道什么类型 InnerEntity 是的成员,但要知道 那个 ,必须推断 阿尔茨海默病 .

    您可以将此函数作为朋友函数模板放入 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);
      }
    
    };
    

    您还可以在中声明一些成员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 类型,如上所述 我的功能 . 在这种情况下,你最好接受 typename AInner 而且写得少。斯芬纳仍将确保只接受正确的事情。