Есть ли способ сохранить пакеты параметров шаблона и использовать их позже? - PullRequest
5 голосов
/ 27 февраля 2020

У меня очень длинный пакет параметров. Интересно, есть ли способ сохранить пакет параметров и использовать его позже. Например, если есть 2 шаблона:

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

У меня есть специализированный тип:

typedef A<int, int, float> A1_t;

Может ли какая-либо операция позволить мне создать специализированный тип B, который использует тот же параметр упаковать как A1_t? (B<int, int, float>). Есть ли способ извлечь <int, int, float> из A1_t или сохранить его?

Я хочу получить специализированный тип B1_t вместо создания объекта B1_t.

A и B описывает совершенно другую концепцию поэтому я не могу сделать B вложенным в A.

, более того, я бы также хотел передать пакеты параметров для специализированных шаблонов функций.

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

, чтобы я мог напрямую вызвать func1<int, int, float>() It было бы хорошо, если бы я мог сделать что-то вроде этого:

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

следующий шаг будет примерно таким:

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

Так что я могу сделать func2<A1_t>(1, 2, 3.0f) напрямую.

1 Ответ

7 голосов
/ 27 февраля 2020

Как то так? Использование преобразования типа на основе частичной специализации:

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

Это ограничено шаблонами классов, которые не используют нетиповые аргументы шаблона. К сожалению, в настоящее время нет способа определить параметры шаблона шаблона, которые принимают как типовые, так и нетиповые параметры шаблона в одном и том же параметре шаблона шаблона.

Также остерегайтесь аргументов по умолчанию. Это не будет использовать аргументы OtherTmpl по умолчанию, если один из аргументов Tmpl по умолчанию соответствует этой позиции в списке шаблонов, и потерпит неудачу, если список шаблонов Tmpl (включая аргументы по умолчанию) больше OtherTmpl s.


Что касается дополнительных примеров в вашем редактировании:

Второй пример работает непосредственно с преобразованием типа, которое я определил выше:

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

Третий это можно сделать так:

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

Это гарантирует, что возвращаемый тип имеет те же аргументы шаблона, что и A1_t, но он принимает все типы в качестве аргументов, даже если они не соответствуют типам в аргументах шаблона A1_t. Это обычно не должно быть проблемой. Если типы не могут быть преобразованы в правильные, вы получите ошибку в том месте, где вы пытаетесь выполнить преобразование.

Если вы должны принять те же типы, что и в аргументах шаблона A1_t для параметров функции вы можете сделать что-то вроде (не проверено):

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