На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Шаблон для типов с разными явными конструкторами , Как сделать конструктор такого шаблона
    Допустим, имеем некие классы a и b, которые имеют явные конструкторы с разным набором параметров. Пусть будет так:
    ExpandedWrap disabled
      class a
      {
      public:
          a(int param_1);
      }
       
      class b
      {
      public:
          b(int param_1, int param_2);
      }

    теперь я хочу написать шаблон класса c, который будет инстанцироваться этими классами и будет от них наследоваться:
    ExpandedWrap disabled
      template <typename T>
      class c : public T
      {
      public:
          c (????)'
          : T(????)
          {}
      }
    т.е. конструктору этого шаблона мне надо передать те же параметры, которые ожидают конструкторы параметра шаблока и в конструкторе вызвать конструктор базового класса с этими параметрами.
    Т.е. я хочу делать так:
    ExpandedWrap disabled
      c<a> Ca(1);
      c<b> Cb(2,3);

    Это вообще возможно? Параметры конструктора в общем случае очень разных типов (указатели на разные типы, целые числа и т.п.), т.е. привести все конструкторы базовых классов к одинаковому виду путем добавления фиктивных параметров ну очень не хотелось бы, страдает мое чувство прекрасного. И делать свой шаблон под каждый тип параметра тоже не хотелось бы - вся реализация шаблона для разных классов отличается только этой передачей парметров конструктору базового класса. Единственное, что приходит в голову - воткнуть в шаблон конструкторы для всех возможных параметров, но как-то это тоже некрасиво.

    Может несколько сумбурно изложил, не пинайте, готов ответить на уточняющие вопросы.
      ExpandedWrap disabled
        template <typename T>
        class c : public T
        {
          using T::T;
          /* ... */
        };
      не работает?

      Добавлено
      P.S. Т.н. наследование конструкторов.
        Не знаю, не пробовал. Решение красивое. А если мне надо в конструкторе сделать что-то еще? Например, проинициализировать поля класса c?
          Может быть как то так?
          ExpandedWrap disabled
            #include <iostream>
             
            class SomeA
            {
            public:
                SomeA(int param1)
                {
                    std::cout << "SomeA: " << param1 << std::endl;
                }
            };
             
            class SomeB
            {
            public:
                SomeB(int p1, int p2)
                {
                    std::cout << "SomeB: " <<  p1 << " "<< p2 << std::endl;
                }
            };
             
            class SomeC
            {
            public:
                SomeC(int p1, int p2, bool p3)
                {
                    std::cout << "SomeC: " << p1 << " " << p2 << " " << p3 << std::endl;
                }
            };
             
             
            template<class T>
            class X : public T
            {
            public:
                template<class...U>
                X(U... args)
                : T(args...)
                {
                }
            };
             
            int main()
            {
                X<SomeC> c(1, 2, false);
                return 0;
            }

          https://ideone.com/7dc9gF

          Я не силен в вариадиках, но такой вариант вроде как работает. Возможно есть какие то грабли....
            Wound, спасибо! То, что нужно! Придется мне тоже учить вариадики.
              Наследование конструкторов появилось в C++11. Немного неправильно его так называть, но называют так. Фактически сия конструкция только переносит сигнатуры конструкторов базового класса в производный. Их действие ограничивается только вызовом соответствующих "базовых" конструкторов, при этом остальные поля конструируются по умолчанию. Если это не устраивает, можно дополнительно воспользоваться другой фичей: делегацией конструкторов.
              ExpandedWrap disabled
                template <typename T>
                class c : public T
                {
                  using T::T;
                 
                public:
                  template <typename ...Args>
                  c(Args&& ...args): c(std::forward<Args>(args)...) {};
                  /* ... */
                };
              Тут есть нюанс: объект будет считаться сконструированным, когда отработает делегируемый конструктор. Поэтому если в теле делегирующего конструктора ожидаются исключения, деструктор создаваемого объекта будет вызван.
                И если не будет слишком большой наглостью с моей стороны, как добавить к конструктору X дополнительные аргументы? Вот так работает:
                ExpandedWrap disabled
                      template<class...U>
                      X(int p4, U... args)
                      : T(args...)
                      {
                          std::cout << "X: " << p4 << std::endl;
                      }
                а хотелось бы дополнительные аргументы добавить в конец. Буду, конечно, читать про вариадики, но может кто-то подскажет быстрее?
                  Цитата Dushevny @
                  хотелось бы дополнительные аргументы добавить в конец
                  Это возможно... но я бы пока не советовал. Сложно без практики будет разобраться. Могу намекнуть на sizeof...() и std::tuple<>.
                    Цитата Qraizer @
                    Это возможно... но я бы пока не советовал
                    Понял. Тогда, действительно, пока не стОит.
                      Приветствую всех снова. Все было просто замечательно, пока мне не потребовалось передать в конструктор ссылку на массив из N элементов. Конструктор шаблона неявно преобразует имя массмва в указатель на первый элемент, а потом компилятор ругается, что у базового класса нет конструктора с таким указателем.
                      ExpandedWrap disabled
                        #include    <utility>
                         
                        using param = int volatile[2];
                        class a
                        {
                        public:
                            a(param &)  {};
                        };
                         
                        class b : public a
                        {
                        public:
                            template <typename ...Args>
                            b(Args ...args)
                            : a(std::forward<Args>(args)...)
                            {}
                        };
                         
                        param P = {1, 2};
                        a A(P);
                        b B(P);


                      ExpandedWrap disabled
                        test.cpp: In instantiation of 'b::b(Args ...) [with Args = {volatile int*}]':
                        test.cpp:21:6:   required from here
                        test.cpp:15:36: error: no matching function for call to 'a::a(volatile int*)'
                           15 |     : a(std::forward<Args>(args)...)
                              |                                    ^
                        test.cpp:7:5: note: candidate: 'a::a(volatile int (&)[2])'
                            7 |     a(param &)  {};
                              |     ^
                        test.cpp:7:7: note:   no known conversion for argument 1 from 'volatile int*' to 'volatile int (&)[2]'
                            7 |     a(param &)  {};
                              |       ^~~~~~~
                        test.cpp:4:7: note: candidate: 'constexpr a::a(const a&)'
                            4 | class a
                              |       ^
                        test.cpp:4:7: note:   no known conversion for argument 1 from 'volatile int*' to 'const a&'
                        test.cpp:4:7: note: candidate: 'constexpr a::a(a&&)'
                        test.cpp:4:7: note:   no known conversion for argument 1 from 'volatile int*' to 'a&&'

                      Не хочу переписывать конструктор базового класса на указатель, потому что тогда можно будет передавать массив из произвольного количества элементов, а я хочу получать от компилятора по рукам, если количесво элементов в массиве отличается от N.

                      Что посоветуете? Может можно каким-нибудь std::что_то<param &>(P) запретить неявное преобразование к указателю?
                      Сообщение отредактировано: Dushevny -
                        Ты где-то потерял универсальную ссылку:
                        ExpandedWrap disabled
                              template <typename ...Args>
                              b(Args&& ...args)
                              : a(std::forward<Args>(args)...)
                              {}

                        P.S. К указателям не сводятся ссылки, а использование в шаблонах универсальных ссылок совместно с форвардом восстанавливает исходный тип в точности. Принимая же параметры по значению вместо ссылки, ты разрешаешь компилятору выполнить сведение, что он и делает, сводя массив к указателю, т.к. массивы по значению передавать нельзя.
                        Сообщение отредактировано: Qraizer -
                          Цитата Qraizer @
                          Ты где-то потерял универсальную ссылку:
                          "Семен Семеныч!" Это я пример от Wound взял. Спасибо!
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0370 ]   [ 17 queries used ]   [ Generated: 19.03.24, 11:17 GMT ]