【问题标题】:Restrict variadic function template to only accept variations of one variadic class template's nested variadic class template?限制可变参数函数模板只接受一个可变参数类模板的嵌套可变参数类模板的变体?
【发布时间】:2010-12-10 22:14:57
【问题描述】:

我有一个可变参数类模板,它有一个嵌套可变参数类模板。外部类模板有一个函数模板,它接受任意数量的参数并将返回一个内部类型的对象。我的问题是创建一个完全独立的函数,该函数将接受这些内部类型的任意数量的任何变体(并且仅接受内部类型),而不管外部类型的变体如何,同时仍确保函数接受的类型是嵌套成员只有那个外部类模板。不知道我解释得是否充分......这基本上是我正在使用的:

template<typename... ArgsOuter> class Outer {
    typedef Outer<ArgsOuter...> outer_t;

    template<typename... ArgsInner> class Inner {
        //static const outer_t* outer;
        typedef outer_t outer;

        Inner(const ArgsInner&... args_inner) {
            //do stuff
        }
    };

    /*
      What's passed in here will be related to and will be a subset of
      the types used to define the Outer class, but I'm not really
      concerned about checking what's being passed in right now.
    */
    template<typename... ArgsFunc>
    make_inner(ArgsFunc... args_func) {
        return Inner<ArgsFunc...> (args_func...);
    }
};

struct ThingA : Outer<int, int, float> {
};

struct ThingB : Outer<int, string, int> {
};

struct ThingC : Outer<string, string, int, int> {
};

//struct ThingN : Outer<random types...> {}

//...meanwhile, over at main...

ThingA tA;
ThingB tB;
ThingC tC;

auto tA_inner = tA.make_inner(1, 1.1);
auto tB_inner = tB.make_inner(2, "foo");
auto tC_inner = tC.make_inner("bar", 2, "foobar");

//mystery_func() is the function I'm not sure how to define.
auto meatloaf = mystery_func(tA_inner, tB_inner, tC_inner);

有人对此有 SFINAE 或可变参数函数模板(或其他)解决方案吗?

【问题讨论】:

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


    【解决方案1】:

    我认为这实际上是不可能的。你似乎想要的是能够做这样的事情:

    template < typename ... Args1, typename ... Args2, typename ... Args3>
    ?? mystery_func(Inner<Args1...>,Inner<Args2...>,Inner<Args3...>);
    

    我认为你做不到。如果可以,那么这就是你的答案。

    既然我怀疑你能做到这一点,你必须做的只是取三种不同的类型,然后使用 SFINAE 来测试它们是 Inners,这就像使用基本的 is_a 元函数一样简单:

    template < typename T > is_inner : boost::mpl::false_ {};
    template < typename ... Pack > is_inner< Inner<Pack...> > : boost::mpl::true_ {};
    

    【讨论】:

    • 好吧,我在想,如果我可以将 Outer 和 Inner 的一个实例隔离在一起,那么可变参数函数模板可以处理我想做的事情,但我没有太多经验构建那些(简单的,当然,但不像这样大声笑)。另一方面,我知道 SFINAE 可以处理一组神秘函数的参数,但我不知道如何为 N 个参数设置它。
    • 我很确定你不可能以第一种方式做到这一点。第二种方法很简单,只需接受一组 Args 并确保所有参数的 is_inner 都是 true。
    • 我花了几天时间进一步研究这个问题,我想我有一个解决方案。我已经发布了一个答案,显示了我所做的事情。老实说,我并没有打算只回答我自己的问题,所以我改变我接受的答案并没有任何意义。我赞成你的回答,因为它让我思考了正确的方向(或者我认为是正确的方向,我的解决方案可能只是垃圾,但它似乎有效。)无论如何,请随意戳洞和批评:)
    【解决方案2】:

    好吧,我并没有打算回答我自己的问题,但我想我在过去几天里一直在努力解决这个问题......当然也学到了一些新东西方式(那里没有投诉)。这有点像丑小鸭(SFINAE + 类型特征元函数 + 可变参数函数模板),但我运行了一些简单的测试,它似乎按预期工作。

    //Use SFINAE to limit the types accepted
    template<typename A, typename Result>
    struct require_1_type { };
    
    //Limit to Outer class
    template<typename... ArgsA, typename Result>
    struct require_1_type<Outer<ArgsA...>, Result> {
        typedef Result type;
    };
    
    //Zero argument, base case for variadic function template.
    void mystery_func() {}
    
    //Recursive portion of variadic function template.
    template<template<typename...> class First, typename... ArgsA, typename... Others>
    typename std::enable_if<
        std::is_same<
            First<ArgsA...>
            , typename require_1_type<
                typename First<ArgsA...>::outer_t
                , typename First<ArgsA...>::outer_t::template Inner<ArgsA...>
            >::type
        >::value
        , some_lib::list<First<ArgsA...>, Others...>
    >::type
    mystery_func (First<ArgsA...> first, Others... others) {
        mystery_func(others...);
        return some_lib::make_list(first, others...);
    }
    

    我的目标是将传入的类型限制为 Inner 的任何变体,以及 Outer 的任何变体。我认为这符合我的要求,至少看起来是这样。

    我对这一切如何运作的理解如下,请酌情更正:

    一系列Inner 对象被传入。每个Inner 对象都有一个引用其'Outer 类型的typedef。我们从参数包中剥离一个Inner 对象,并检查引用其Outer 类型的typedef,以确保它与预期的Outer 类型匹配。如果匹配,则我们获取传入的第一个 Inner 对象上使用的参数包,并将该包传递给我们通过第一个 @987654331 引用的 Outer 类型定义引用的 Inner 模板@。然后我们检查这两个Inner 以确保它们是相同的。如果是,则启用特定的函数模板实例化。

    可变参数函数模板本身只是递归地调用自己,这样参数包中的所有对象都会对它们进行相同的检查,直到我们用完参数,这会调用函数的空白版本。最后,每次递归都会调用(在这种情况下)一个将对象放在一个列表中的函数。

    我不确定的一件事是编译器是否正在优化所有对 make_list 的调用,这些调用返回虚无,除了最后一个,它是由第一次调用 mystery_func() 完成的,也是唯一的一个有一个有目的的返回值。

    无论如何,我们欢迎改进、cmets 和简化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-15
      • 2021-10-01
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      相关资源
      最近更新 更多