Есть ли способ получить доступ ко всему, кроме последнего параметра шаблона? - PullRequest
3 голосов
/ 02 апреля 2019

Пакет параметров шаблона можно использовать следующим образом:

template <int T1, int... Ts>
struct Test {
  static constexpr int sizes[] = {Ts...};
};

template <int T1, int... Ts>
constexpr int Test<T1, Ts...>::sizes[];

Однако, как указано здесь , пакет параметров шаблона должен быть последним параметром шаблона. Следовательно, мы не можем иметь такой код:

template <int T1, int... Ts, int Tn>
struct Test {
  static constexpr int sizes[] = {Ts...}; 
  Foo<Ts...> foo;
};

template <int T1, int... Ts, int Tn>
constexpr int Test<T1, Ts..., Tn>::sizes[];

Во многих случаях нам нужен доступ к последнему элементу набора параметров шаблона. У меня вопрос, какова лучшая практика для реализации вышеуказанного кода?

Edit: Это не дубликат этого вопроса . Я пытаюсь получить все, кроме последнего параметра (не самого последнего параметра), поскольку мне нужно определить Foo следующим образом:

  Foo<Ts...> foo;

Ответы [ 3 ]

3 голосов
/ 02 апреля 2019

Вы можете использовать стандартный метод использования std::index_sequence

template<template<auto...> typename Tmp, size_t... Is, typename... Args>
constexpr auto take_as(std::index_sequence<Is...>, Args...)
{
    using Tup = std::tuple<Args...>;
    return Tmp<std::tuple_element_t<Is, Tup>{}...>{};
}

template<auto... Vals>
struct except_last
{
    template<template<auto...> typename Tmp>
    using as = decltype(take_as<Tmp>(std::make_index_sequence<sizeof...(Vals) - 1>{},
                                     std::integral_constant<decltype(Vals), Vals>{}...));
};

, который вы используете как

using F = except_last<1, 2, 3, 4>::as<Foo>;  // F is Foo<1, 2, 3>

Это легче реализовать и прочитать, но вы потенциально получаетеO (n) глубина создания.Если вы одержимы эффективностью, вы можете сделать O (1) глубину инстанцирования, используя выражения складывания

template<typename T>
struct tag
{
    using type = T;
};

template<typename F, typename... Ts>
using fold_t = decltype((F{} + ... + tag<Ts>{}));

template<size_t N, typename... Ts>
struct take
{    
    template<typename T>
    auto operator+(tag<T>) -> take<N - 1, Ts..., T>;
};

template<typename... Ts>
struct take<0, Ts...>
{
    template<template<auto...> typename Tmp>
    using as = Tmp<Ts{}...>;

    template<typename T>
    auto operator+(tag<T>) -> take<0, Ts...>;
};

template<auto... Vals>
struct except_last
{
    template<template<auto...> typename Tmp>
    using as = fold_t<take<sizeof...(Vals) - 1>,
                      std::integral_constant<decltype(Vals), Vals>...>::template as<Tmp>;
};
0 голосов
/ 02 апреля 2019

integer_sequence - это способ:

template <typename SeqN, typename Seq> struct TestImpl;

template <int... Ns, std::size_t ... Is>
struct TestImpl<std::integer_sequence<int, Ns...>, std::index_sequence<Is...>>
{
private:
    using SeqTuple = std::tuple<std::integral_constant<int, Ns>...>;
public:
  static constexpr int sizes[] = {std::tuple_element_t<Is, SeqTuple>::value...}; 
  Foo<std::tuple_element_t<Is, SeqTuple>::value...> foo;
};


template <int N1, int N2, int... Ns> // At least 2 numbers
using Test = TestImpl<std::integer_sequence<int, N1, N2, Ns...>,
                      std::make_index_sequence<1 + sizeof...(Ns)>>;

Демо

0 голосов
/ 02 апреля 2019

Какой самый эффективный способ получить доступ к последнему параметру шаблона?

Вы можете использовать маленький помощник для преобразования пакета параметров в массив.

template<int... Args>
struct pack {
    static constexpr std::array as_array{ Args... };
};

Затем вы можете получить последний аргумент с индексацией массива:

template <int T1, int... Ts>
struct Test {
    static constexpr int last = pack<Ts...>::as_array[sizeof...(Ts) - 1];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...