5

I have very long parameter pack. I wonder is there any way to store the parameter pack and reuse it later. For example, if there are 2 templates:

template<class ... Types> struct A {};
template<class ... Types> struct B {};

I have a specialized type:

typedef A<int, int, float> A1_t;

Is there any operation can let me create a specialized type B which use the same parameter pack as A1_t? (B<int, int, float>). Is there any method to retrieve the <int, int, float> from A1_t or store it?

I want obtain a specialized type B1_t instead of creating the object of B1_t.

A and B describes completely different concept, so I cannot make B nested inside A.

moreover, I would also like to feed the parameter packs to specialize function templates.

template<class ...Ts>
C<Ts...> func1()
{
}

so I can directly call func1<int, int, float>() It will be nice if I can do something like this:

template<typename T>
transform<B, T> func1()
{
}

next step would be something similar to this:

template<template<class...Ts> templ>
B<Ts...> func2(Ts ...args)
{
}

So I can do func2<A1_t>(1, 2, 3.0f) directly.

Wang
  • 7,250
  • 4
  • 35
  • 66
  • 1
    `template B makeB(const A&)` ? – jtbandes Feb 27 '20 at 02:17
  • What about making `B` be a nested type of `A` so it can share `A`'s template parameters? – Remy Lebeau Feb 27 '20 at 02:18
  • Are you asking for the means of taking some instance of the `A` template, and get the `B` template with the same template parameters? I.e., if you have `A`, to "translate" it into `B`? If not, what do you mean, exactly by "storing it"? – Sam Varshavchik Feb 27 '20 at 02:22
  • Also, what do you mean by the last sentence. Can you provide an concrete example, except for the missing bits, of what you're starting with, and what you expect your end result to be. – Sam Varshavchik Feb 27 '20 at 02:28
  • Does this answer your question? [Is it possible to "store" a template parameter pack without expanding it?](https://stackoverflow.com/questions/4691657/is-it-possible-to-store-a-template-parameter-pack-without-expanding-it) – c z Aug 24 '23 at 13:02

1 Answers1

8

Something like this? Using a type transformation based on partial specialization:

#include<type_traits>

template<template<typename...> class, typename>
struct with_tmpl_args_of;

template<template<typename...> class OtherTmpl, template<typename...> class Tmpl, typename... Args>
struct with_tmpl_args_of<OtherTmpl, Tmpl<Args...>> {
    using type = OtherTmpl<Args...>;
};

template<template<typename...> class OtherTmpl, typename T>
using with_tmpl_args_of_t = typename with_tmpl_args_of<OtherTmpl, T>::type;

// example

template<class ... Types> struct A {};
template<class ... Types> struct B {};

using A1_t = A<int, int, float>;

using B1_t = with_tmpl_args_of_t<B, A1_t>;

// test

static_assert(std::is_same_v<B1_t, B<int, int, float>>);

This is limited to class templates that do not use non-type template arguments. There is currently unfortunately no way to define template template parameters which accept both type and non-type template parameters in the same template template parameter's parameter.

Also beware of default arguments. This will not use OtherTmpl's default arguments, if one of Tmpl's default arguments matches that position in the template list and will fail if Tmpl's template list (including defaulted arguments) is larger than OtherTmpls.


Regarding the additional examples in your edit:

The second example works directly with the type transform I defined above:

template<typename T>
with_tmpl_args_of_t<B, T> func1()
{
}

The third one can be done like this:

template<typename A, typename... Ts>
with_tmpl_args_of_t<B, A> func2(Ts... args)
{
}

It guarantees that the return type has the same template arguments as A1_t, but it does accept all types as arguments, even if they don't match the types in the template arguments of A1_t. This should not usually be a problem. If the types are not convertible to the correct ones you will get an error at the point where you try the conversion.

If you must take the exact same types as in the template arguments of A1_t for function parameters, you can do something like (untested):

template<typename T>
struct func_with_tmpl_args_of;

template<template<typename...> class Tmpl, typename... Args>
struct func_with_tmpl_args_of<Tmpl<Args...>> {
    template<typename F>
    struct inner {
        constexpr inner(F f) : f(std::move(f)) {}
        constexpr static decltype(auto) operator()(Args... args) const {
            return f(std::forward<Args>(args)...);
        }
    private:
        F f;
    };
};

// example

template<typename T>
constexpr inline auto func2 = func_with_tmpl_args_of<T>::inner{[](auto... args)
  -> with_tmpl_args_of_t<B, T> {
    // actual function body
}};
walnut
  • 21,629
  • 4
  • 23
  • 59
  • this is amazing! I think there is no way to use same tech to specialize function template? Probably I can try to switch to template functors. Is there any library such as fusion or hana provide similar feature? – Wang Feb 27 '20 at 02:47
  • @Wang You need to give an example of what you mean with "*specialize function template"*. It is not clear to me what you mean. I don't know about the libraries. I would need to check the documentations. The use of this is rather limited I think, so probably they don't. – walnut Feb 27 '20 at 02:48
  • I just want to give you credit. I published your sentence "_There is currently unfortunately no way to define template template parameters which accept both type and non-type template parameters in the same template template parameter's parameter._" together with an old swedish saw a'la "_what would a woodpecker ...._" on my FB page tonight. It got a chuckle from programmers and non-programmers alike :-) – Ted Lyngmo Feb 27 '20 at 20:10