Ошибка удержания параметров шаблона аргумента шаблона шаблона - PullRequest
0 голосов
/ 25 июня 2018

У меня проблемы при написании членов шаблона не шаблонного класса, особенно при выводе параметров шаблона аргумента шаблона шаблона.

Следующий код, минимальный, иллюстрирует мою проблему.Я подозреваю, что есть как минимум две разные проблемы.

#include <iostream>
#include <list>

using namespace std;

struct A
{
    list<int> l;

    template<template<class> class Iterable> 
    A(Iterable<int>& it);
};

template<template<class> class Iterable>
A::A(Iterable<int>& it) : l(list<int>())
{
    for(int i : it)
        l.push_back(i);
}

int main()
{
    list<int> l = {1, 2, 3, 4};
    A a(l);
    for(int i : a.l)
        cout << i << " ";
     cout << endl;

    A b = {1, 2, 3, 4};
    for(int i : b.l)
        cout << i << " ";
    cout << endl;
}

Замечания: Я действительно хочу дать определение вне класса.Я также хочу, чтобы прототип конструктора A работал со списками целых чисел, векторами целых чисел, а также со списком инициализаторов.

1 Ответ

0 голосов
/ 25 июня 2018

Я подозреваю, что там как минимум две разные проблемы.

Правильно: я вижу три разные проблемы.

1) std::list потребности два параметра шаблона;второй по умолчанию (std::allocator<T>, где T - первый параметр шаблона);а также векторам, запросам, наборам и т. д. требуется больше, чем параметр шаблона (некоторые по умолчанию).

То есть template<template<class> class> не соответствует std::list и другим контейнерам STL.

КомуЕсли говорить более обобщенно, я предлагаю что-то вроде

template <template <typename...> class Iterable, typename ... Ts> 
A (Iterable<int, Ts...> & it);

2) A b = {1, 2, 3, 4}; не работает, потому что вы вызываете конструктор с четырьмя аргументами и у вас есть только конструкторы с одним аргументом.Таким образом, вы должны явно указать контейнер как

A b = std::list<int>{1, 2, 3, 4};

Учитывая, что вы ожидаете std::initializer_list в качестве контейнера по умолчанию, если вы соглашаетесь удваивать графики ({ { 1, 2, 3, 4 } } вместо { 1, 2, 3, 4 } для передачиодин аргумент для конструктора), вы можете указать std::initializer_list (или другой контейнер, если хотите) по умолчанию Iterable.

Я имею в виду ... если вы объявите конструктор следующим образом

   template <template <typename...> class Iterable = std::initializer_list,
             typename ... Ts> 
   A (Iterable<int, Ts...> const & it);

, затем вы можете инициализировать b как

   A b {{1, 2, 3, 4}};

3) подпись Iterable<int, Ts...> & it, в вашем конструкторе шаблона, принять ссылку на l-значение, поэтому принимайте

list<int> l = {1, 2, 3, 4};
A a(l);

, но не принимает

A b = std::list<int>{1, 2, 3, 4};

, поскольку std::list<int>{1, 2, 3, 4} является значением r.

Чтобы решить эту проблему, вы можете написать другой конструктор для ссылок на значения r, но,в этом случае я подозреваю, что приемлемо просто изменить конструкцию шаблона, чтобы она могла принимать const l-значения ссылок

A (Iterable<int, Ts...> const & it); 
// .....................^^^^^

Бонус (не по теме) предложение: если вы 'Заинтересовавшись принятием контейнеров STL, вы можете упростить свой шаблонИспользовать конструктор, используя конструктор l, который принимает пару итераторов (begin(), end()), поэтому

template <template <typename...> class Iterable, typename ... Ts>
A::A (Iterable<int, Ts...> const & it) : l{it.cbegin(), it.cend()}
 { }

или также

template <template <typename...> class Iterable, typename ... Ts>
A::A (Iterable<int, Ts...> const & it) : l{std::cbegin(it), std::cend(it)}
 { }

Ниже приведен ваш кодмодифицированный

#include <initializer_list>
#include <iostream>
#include <list>

struct A
 {
   std::list<int> l;

   template <template <typename...> class Iterable = std::initializer_list,
             typename ... Ts> 
   A (Iterable<int, Ts...> const & it);
 };

template <template <typename...> class Iterable, typename ... Ts>
A::A (Iterable<int, Ts...> const & it) : l{std::cbegin(it), std::cend(it)}
 { }

int main ()
 {
   std::list<int> l {1, 2, 3, 4};
   A a(l);

   for (auto i : a.l)
      std::cout << i << " ";
   std::cout << std::endl;

   A b {{1, 2, 3, 4}};

   for (auto i : b.l)
      std::cout << i << " ";
   std::cout << std::endl;
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...