Два аргумента шаблона с одинаковым размером - PullRequest
0 голосов
/ 25 ноября 2018

Я хочу реализовать функцию Print, которая работает так:

Print<1, 3>("Hello", "World");

, и я надеюсь, что она напечатает «Hello» один раз и «World» 3 раза. Интересно, как это реализовать.Ниже мой глупый код, конечно, он не сработал при компиляции:

template <unsigned int n, unsigned int ...n_next,
          typename T, typename ...Ts>
void Print(T & t, Ts & ... ts)
{
    for(int i = 0; i < n; i++)
    {
        std::cout << t << " ";
    }
    std::cout << std::endl;

    Print<n_next..., ts...>(ts...);
}

template <unsigned int n, typename T>
void Print(T & t)
{
    for(int i = 0; i < n; i++)
    {
        std::cout << t << " ";
    }
    std::cout << std::endl;
}

Ответы [ 4 ]

0 голосов
/ 25 ноября 2018

Я также предлагаю совершенно другое решение, которое позволяет избежать циклов и рекурсий for().

Он имитирует свертывание шаблонов в C ++ 14 при инициализации неиспользуемого массива в стиле C.

Сначала основной Print(), который расширяет списки переменных, вызывающие вспомогательную функцию Print_h(), передавая ей значения и список (последовательность индексов), соответствующие номерам итераций для каждого значения

template <std::size_t ... Ns, typename ... Ts>
void Print (Ts ... ts)
 {
   using unused=int[];

   (void)unused { 0, (Print_h(std::make_index_sequence<Ns>{}, ts), 0)... };
 }

Затем вспомогательная функция, которая использует один и тот же прием для множественной печати

template <std::size_t ... Is, typename T>
void Print_h (std::index_sequence<Is...>, T const & t)
 {
   using unused=std::size_t[];

   (void)unused { 0, (std::cout << t << " ", Is)... };

   std::cout << std::endl;
 }

Ниже приведен пример полной компиляции C ++ 14

#include <utility>
#include <iostream>

template <std::size_t ... Is, typename T>
void Print_h (std::index_sequence<Is...>, T const & t)
 {
   using unused=std::size_t[];

   (void)unused { 0, (std::cout << t << " ", Is)... };

   std::cout << std::endl;
 }

template <std::size_t ... Ns, typename ... Ts>
void Print (Ts ... ts)
 {
   using unused=int[];

   (void)unused { 0, (Print_h(std::make_index_sequence<Ns>{}, ts), 0)... };
 }

int main ()
 {
   Print<1u, 3u>("hello", "world");
 }

Если вы не можете использовать C ++14, но только C ++ 11, не сложно разработать заменители для std::make_index_sequence и std::index_sequence (оба доступны только для C ++ 14).

Очевидно, что в C ++ 17 вы можете использовать шаблонскладывание упрощает функции следующим образом

template <std::size_t ... Is, typename T>
void Print_h (std::index_sequence<Is...>, T const & t)
 {    
   ((std::cout << t << " ", (void)Is), ...);

   std::cout << std::endl;
 }

template <std::size_t ... Ns, typename ... Ts>
void Print (Ts ... ts)
 { (Print_h(std::make_index_sequence<Ns>{}, ts), ...); }
0 голосов
/ 25 ноября 2018

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

template <unsigned int n, typename T>
void Print(T & t)
{
    for(unsigned int i = 0; i < n; i++)
    {
        std::cout << t << " ";
    }
    std::cout << std::endl;
}

template <unsigned int n, unsigned int ...n_next,
          typename T, typename ...Ts>
void Print(T & t, Ts & ... ts)
{
    for(unsigned int i = 0; i < n; i++)
    {
        std::cout << t << " ";
    }
    std::cout << std::endl;

    Print<n_next...>(ts...);
}

(также, будьте последовательны со знаком)
Демо

Более того, вам не нужно дублировать печатную часть, просто вызовите другую перегрузку:

template <unsigned int n, typename T>
void Print(T & t)
{
    for(unsigned int i = 0; i < n; i++)
    {
        std::cout << t << " ";
    }
    std::cout << std::endl;
}

template <unsigned int n, unsigned int ...n_next,
          typename T, typename ...Ts>
void Print(T & t, Ts & ... ts)
{
    Print<n>(t);
    Print<n_next...>(ts...);
}

В качестве альтернативы, если вы можете использовать C ++17 для выражений сгиба, вы можете сделать следующее (используйте ссылки переадресации и std::forward, если вам нужно):

template<typename T>
void Print(unsigned int n, T& t)
{
    for(unsigned int i = 0; i < n; i++)
    {
        std::cout << t << " ";
    }
    std::cout << std::endl;
}

template<unsigned int... Ns, typename... Ts>
void Print(Ts&... ts)
{
    (Print(Ns, ts), ...);
}

Демо

0 голосов
/ 25 ноября 2018

Я вижу четыре проблемы в вашем коде

(1) рекурсивный вызов

Print<n_next..., ts...>(ts...);

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

Print<n_next..., Ts...>(ts...);

или, что лучше (потому что разрешить трюк, который я объясню далее) без объяснения типов

Print<n_next...>(ts...);

(2) лучше, если вы получите как const ссылается на значения

template <unsigned int n, unsigned int ...n_next,
          typename T, typename ...Ts>
void Print(T const & t, Ts ... ts)
// ..........^^^^^

, иначе вы не можете вызвать Print() с постоянными значениями следующим образом

Print<1u, 3u>(1, "world");

(3) лучше использовать значение без знака для индексов в forциклы, потому что вы должны проверить их со значениями без знака (незначительная проблема)

// ..VVVVVVVV
for (unsigned int i = 0; i < n; i++)

(4) вы должны поместить наземный регистр для Print() (тот, который получает только значение) перед рекурсивный случай.

Я предлагаю заменить их на

template <typename = void>
void Print ()
 { }

, потому что, таким образом, все распечатки выполняются в рекурсивной версии и вам не нужно повторять одинаковый кодв двух разных функциях (но вы должны вызвать Print<n_next...>(ts...); рекурсию.

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

#include <iostream>

template <typename = void>
void Print ()
 { }

template <unsigned int n, unsigned int ...n_next,
          typename T, typename ...Ts>
void Print(T const & t, Ts ... ts)
{
    for(auto i = 0u; i < n; i++)
     {
       std::cout << t << " ";
     }

    std::cout << std::endl;

    Print<n_next...>(ts...);
}

int main ()
 {
   Print<1u, 3u>("hello", "world");
 }
0 голосов
/ 25 ноября 2018

Это сделает это:

template <unsigned int n, typename T>
void Print(T&& t)
{
    for(int i = 0; i < n; i++)
    {
        std::cout << std::forward<T>(t) << " ";
    }
    std::cout << std::endl;
}

template <std::size_t Idx1, std::size_t... Idx, class T, class... Ts>
void Print(T&& t, Ts&& ... ts) {
    Print<Idx1>(std::forward<T>(t));

    using expand = int[];
    (void)expand{(Print<Idx>(std::forward<Ts>(ts)), 0) ...};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...