На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> шаблонный конструктор шаблонного класса да еще и с разным числом аргументов , не знаю, как написать.
    имеется шаблонный класс:
    ExpandedWrap disabled
      template<typename payload>
      class message
      {
      public:
          template<typename source>
          message(int param1, source param2);
          
      private:
          payload Payload;
      };

    для разных специализаций этого шаблона я пишу разные конструкторы:
    ExpandedWrap disabled
      template<> template<typename source>
      message<a>::message(int param1, source param2)
      {
       
      }
       
      template<> template<>
      message<b>::message(int param1, bool param2)
      {
       
      }

    но для одной из специализаций мне потребовался дополнительный параметр конструктора. Я, конечно, могу в исходный шаблон добавить второй конструктор с тремя аргументами, но считаю это не лучшим решением, потому что завтра мне для какой-то еще специализации может понадобится еще один аргумент и придется дописывать еще один конструктор. Попытался использовать variadic templates:
    ExpandedWrap disabled
      ....
      public:
          template<typename ...Args>
          message(int param1, Args ...args);
      ....


    почти все хорошо: я могу описать полную специалзацию с любым количеством параметров:
    ExpandedWrap disabled
      template<> template<>
      message<с>::message(int param1, int param2, bool param3)
      {
       
      }

    но мне нужно, чтобы один из параметров оставался шаблонным, то есть получить что-то вроде
    ExpandedWrap disabled
      template<> template<typename source>
      message<d>::message(int param1, source param2)
      {
       
      }
      template<> template<typename source>
      message<e>::message(int param1, int param2, source param3)
      {
       
      }
    Как это сделать? Если такое вообще возможно...
      Цитата Dushevny @
      Я, конечно, могу в исходный шаблон добавить второй конструктор с тремя аргументами, но считаю это не лучшим решением, потому что завтра мне для какой-то еще специализации может понадобится еще один аргумент и придется дописывать еще один конструктор.
      Ты можешь его объявить, но реализовывать его будет только та специализация, которая сочтёт это нужным ей. Вызов такого конструктора для любой другой специализации вызовет ошибку линковки.
      Цитата Dushevny @
      Попытался использовать variadic templates:
      Я бы не стал считать это решение лучшим предыдущего. Скорее наоборот, оно неинуитивнее, ибо непонятнее зачем оно нужно. В специальном конструкторе смысл видится яснее. И скорее даже будет меньше вопросов "зачем он тут" по сравнению "что это вообще такое", если увидят вариадик. Но это субъективно, и зависит от конкретики ситуации.

      Добавлено
      P.S. Вообще же, это какая-то странная задача, когда надо для каждой пары шаблонных параметров мутить отдельные специализации. Обычно шаблоны используются с точностью до наоборот. Ты точно не мультиметоды пытаешься изобрести?
        Qraizer, спасибо. Пожалуй, вы правы и оба решения хуже.
        Как говорится "стоило написать вопрос и тут же сам нашел ответ". Он, правда, не лучше первых двух, но в данной задаче меня устраивает - сделал наследника от нужной специализации, в конструкторе наследника обрабатываю "лишний" аргумент, в конструкторе специализации - два общих аргумента.

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

        Добавлено
        Цитата Qraizer @
        Вообще же, это какая-то странная задача, когда надо для каждой пары шаблонных параметров мутить отдельные специализации. Обычно шаблоны используются с точностью до наоборот. Ты точно не мультиметоды пытаешься изобрести?
        Про мультиметоды даже не слышал, сейчас почитаю. Задача проста как грабли - имеется куча разных сообщений. Все они наследники одного базового класса, в котором определены виртуальные функции работы с этими сообщениями - распечатать, сравнить, отослать дальше. Каждый тип сообщения во входном потоке закодирован по-своему, конструктор разбирает входной поток и заполняет поля сообщения. А параметр этого потока шаблонный, потому что работа с этими сообщениями используется в разных программах и в одной из них входной поток - массив байтов, в других - массив классов (для каждого типа сообщений свой класс), для которых переопределен оператор приведения к байту.
        Сообщение отредактировано: Dushevny -
          Выглядит как будто тебе нужна перегрузка, а не специализация.
            Фактически, да. Но объявление всех классов-наследников одинаковы (кроме конструктора в некоторых случаях), поэтому я обернул их в шаблон.

            Впрочем, ночью понял, что перемудрил с решением и буду все переделывать.
              Пожалуй, шаблоны тут вообще не нужны. Достаточно обычного полиморфизма.
                хорошо. Допустим, вот типы сообщений:
                ExpandedWrap disabled
                  struct a { int a; };
                  struct b { char b; };
                  struct c { long c; };

                вот базовый класс:
                ExpandedWrap disabled
                  class generic_msg
                  {
                  public:
                      virtual void show() const = 0;
                      virtual void send() const = 0;
                  };

                вот решение с полиморфизмом:
                ExpandedWrap disabled
                  class msg_a : public generic_msg
                  {
                  public:
                      void show() const override;
                      void send() const override;
                  private:
                      a   Payload;
                  };
                   
                  class msg_b : public generic_msg
                  {
                  public:
                      void show() const override;
                      void send() const override;
                  private:
                      b   Payload;
                  };
                   
                  class msg_c : public generic_msg
                  {
                  public:
                      void show() const override;
                      void send() const override;
                  private:
                      c   Payload;
                  };

                Здесь их три, по факту - несколько десятков

                вот решение с шаблонами:
                ExpandedWrap disabled
                  template<typename payload>
                  class msg : public generic msg
                  {
                  public:
                      void show() const override;
                      void send() const override;
                  private:
                      payload   Payload;
                  };

                почему бы их не использовать, если объявление шаблона одно на любое количество типов сообщений, а без шаблона на каждый тип сообщения приходится писать новое объявление потомка, которое отличается только типом поля payload?

                Добавлено
                Шаблоны ведь именно для этого и придуманы.

                Моя архитектурная ошибка была в том, что я заполнение полей сообщений возложил на конструктор, а надо в шаблоне сделать конструктор перемещения, принимающий объект типа payload. А уже этот объект создавать другим набором классов, который свой для каждой программы, использующей работу с этими сообщениями.
                Сообщение отредактировано: Dushevny -
                  Цитата Dushevny @
                  Шаблоны ведь именно для этого и придуманы.
                  Не совсем для этого. Но это неважно. Архитектурная ошибка... даже скорее недочёт, заключается в том, что у тебя по факту два интерфейса, а реализовал ты как интерфейс лишь один, а другой жёстко в него вшит и не выделен как отдельная параметризируемая для него сущность. Для payload тоже надо было бы предусмотреть интерфейс с get()/set(), который бы абстрагировали его репрезентацию. <iostream> помнишь? std::basic_ios<> отдельно, а std::basic_streambuf<> отдельно. Оба находятся в тесной связи, но пульзуют друг друга полиморфно.

                  Добавлено
                  P.S. К слову сказать, тут мультиметод вполне мог бы всплыть как синергия между двумя независимыми деревьями.
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0379 ]   [ 16 queries used ]   [ Generated: 28.03.24, 15:39 GMT ]