限制可变参数函数模板仅接受一个可变参数类模板的嵌套可变参数类模板的变体?

发布于 2024-10-06 23:05:42 字数 1470 浏览 4 评论 0原文

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

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 或可变参数函数模板(或其他)解决方案吗?

I have a variadic class template that has a nested variadic class template. The outer class template has a function template that accepts any number of arguments and will return an object of type inner. My problem is creating a completely separate function that will accept any number of any variation of those inner types (and only the inner types), regardless of the variant of the outer type, while still ensuring that accepted types to the function are nested members of only that outer class template. Not sure if I explained that adequately... Here's essentially what I'm working with:

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

Anyone have an SFINAE or variadic function template (or other) solution for this?

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

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

发布评论

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

评论(2

千纸鹤 2024-10-13 23:05:42

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

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

我不认为你能做到这一点。如果可以的话,这就是你的答案。

因为我怀疑你能做到这一点,所以你要做的就是采用三种不同的类型,然后使用 SFINAE 来测试它们是否是 Inner<> ,这就像使用基本的 is_a 元函数一样简单:

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

I think this might actually be impossible. What you seem to want is the ability to do something like so:

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

I don't think you can do that. If you can, then there's your answer.

Since I doubt you can do that, what you'll have to do instead is just take three different types and then use SFINAE to test that they are Inner<>s, which would be as easy as using a basic is_a metafunction:

template < typename T > is_inner : boost::mpl::false_ {};
template < typename ... Pack > is_inner< Inner<Pack...> > : boost::mpl::true_ {};
为你拒绝所有暧昧 2024-10-13 23:05:42

好吧,我并没有打算回答我自己的问题,但我想我在过去几天里已经把头撞到墙上了,足以解决这个问题......并且一路上当然学到了一些新东西(没有抱怨)。它有点像丑小鸭(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 对象都有一个引用其 Inner 的 typedef 。代码>外部类型。我们从参数包中删除一个 Inner 对象,并检查引用其 Outer 类型的 typedef,以确保它与预期的 Outer 匹配类型。如果匹配,则我们获取传入的第一个 Inner 对象上使用的参数包,并将该包传递给我们通过 Inner 引用的 Inner 模板。 code>Outer typedef 由第一个 Inner 引用。然后我们相互检查这两个 Inner 以确保它们相同。如果是,则启用该特定函数模板实例化。

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

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

不管怎样,改进、评论和简化都是最受欢迎的。

Well, I didn't set out to answer my own question, but I think I've beat my head against the wall just enough the past few days to figure this one out... and certainly learned some new stuff along the way (no complaints there). It's a bit of an ugly duckling (SFINAE + type traits metafunctions + variadic function templates), but I've run a few simple test and it seems to work as expected.

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

My goal was to limit the types being passed in, to any variations of Inner for any variations of Outer. I think this does what I was looking for, at least it seems that way.

My understanding of how this all works is as follows, please correct as appropriate:

A series of Inner objects gets passed in. Each Inner object has a typedef referring to its' Outer type. We strip off one Inner object from the parameter pack, and check the typedef referring to its' Outer type to make sure it matches the expected Outer type. If it matches, then we take the parameter pack used on the first Inner object that was passed in, and pass the pack along to an Inner template that we reference through the Outer typedef referred to by the first Inner. Then we check those two Inner's against each other to make sure they're the same. If they are, then that particular function template instantiation is enabled.

The variadic function template itself simply calls itself recursively so that all objects in the parameter pack have those same checks run on them, until we run out of arguments, which calls the blank version of the function. Finally, each recursion makes a call to (in this case) a function that puts the objects together in a list.

One thing I'm not sure of is if the compiler is optimizing out all those calls to make_list that are returning into nothingness, except the last one, which is done by the first invocation of mystery_func(), and the only one that has a purposeful return value.

Anyway, improvements, comments, and simplifications are most welcome.

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