Re: доступ к патомку через базовый класс
От: Аноним  
Дата: 30.03.06 14:24
Оценка: 3 (1)
Здравствуйте, Nickolas, Вы писали:


N>Есть ли возможность это как-то обойти? Или может есть стандартные приемы для подобных случаев?

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

N>Понятно, что приведенный код работать не будет: в базом классе нет нужного operator <<.

N>Добавить его в базовый класс и сделат виртуальным тоже не получиться, так как он параметризован.
Нам не нужен базовый класс, нам нужна полиморфная функция, написанная единожды и работающая с разными типами

N>В краце хочеться, чтобы каждый стрим мог форматировать данные как ему хочеться.

Предлагаю рассмотреть возможное решение на основе CRTP (curiously recurrent template pattern)


#include <vector>

using namespace std;

template <typename T>
struct basic_stream
{
    template <typename U>    
    std::ostream& operator << (T v)
        {
            return static_cast<T&>(*this).operator<<(v);
        }
};


struct super_stream : basic_stream<super_stream>
{
  template<typename T>
  std::ostream& operator << (T const &v)
  {
    std::cout << "super_stream::operator << (T const &v)" << std::endl;
    return std::cout;
  }

  std::ostream& operator << (int v)
  {
    std::cout << "super_stream::operator << (int v)" << std::endl;
    return std::cout;
  }

  template<typename T>
  std::ostream& operator << (std::vector<T> const &v)
  {
    std::cout << "super_stream::operator << (std::vector<T> const &v)" << std::endl;
    return std::cout;
  }
};

struct another_super_stream : basic_stream<another_super_stream>
{
  template<typename T>
  std::ostream& operator << (T const &v)
  {
    std::cout << "another_super_stream::operator << (T const &v)" << std::endl;
    return std::cout;
  }

  std::ostream& operator << (int v)
  {
    std::cout << "another_super_stream::operator << (int v)" << std::endl;
    return std::cout;
  }

  std::ostream& operator << (double v)
  {
    std::cout << "another_super_stream::operator << (double v)" << std::endl;
    return std::cout;
  }
};

template <typename STREAM_T, typename VALUE_T>
void static_polymorphic_output(STREAM_T& stream, VALUE_T v)
{
    stream << v;
}

int main(int argc, char* argv[])
{
    super_stream            ss;
    another_super_stream    ass;
    std::vector<int>        v;

    static_polymorphic_output(ss,10);
    // output: super_stream::operator << (int v)
    static_polymorphic_output(ass,10);
    // output: another_super_stream::operator << (int v)
    static_polymorphic_output(ss,v);
    // output: super_stream::operator << (std::vector<T> const &v)
    static_polymorphic_output(ass,v);
    // output: another_super_stream::operator << (T const &v)
    static_polymorphic_output(ss,10.);
    // output: super_stream::operator << (T const &v)
    static_polymorphic_output(ass,10.);
    // output: another_super_stream::operator << (double v)

    return 0;
}
Re: доступ к патомку через базовый класс
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 31.03.06 12:47
Оценка: 3 (1)
Здравствуйте, Nickolas, Вы писали:

N>В краце хочеться, чтобы каждый стрим мог форматировать данные как ему хочеться. Но в момент, когда начинается форматирование у меня есть только ссылка на базовый стрим.


Страуструп в таком случае предлагает следующий подход:
struct basic_stream {
    virtual std::ostream& put(std::ostream& s) const {
        s << "basic_stream::put()" << std::endl;
        return s;
    }
};


struct super_stream : basic_stream{
    std::ostream& put(std::ostream& s) const {
        s << "super_stream::put()";
        return s;
    }
};


struct another_super_stream : basic_stream {
    std::ostream& put(std::ostream& s) const {
        s << "another_super_stream::put()";
        return s;
    }
};

std::ostream& operator<<(std::ostream& s, const basic_stream& r) {
    return r.put(s);
}

int main() {
    super_stream ss;
    basic_stream& bs = ss;
    std::cout << bs << std::endl;

    another_super_stream ass;
    basic_stream& bs2 = ass;
    std::cout << bs2 << std::endl;
    return 0;
}
http://denis-zhdanov.blogspot.com
доступ к патомку через базовый класс
От: Nickolas Чехия  
Дата: 29.03.06 13:49
Оценка:
Всем привет. Есть вот такой код:


#include <iostream>
#include <vector>

struct basic_stream
{
  virtual std::ostream& operator << (int v) {}
};


struct super_stream : basic_stream
{

  template<typename T>
  std::ostream& operator << (T const &v)
  {
    std::cout << "operator << (T const &v)" << std::endl;
  }

  virtual std::ostream& operator << (int v)
  {
    std::cout << "operator << (int v)" << std::endl;
  }

  template<typename T>
  std::ostream& operator << (std::vector<T> const &v)
  {
    std::cout << "operator << (std::vector<T> const &v)" << std::endl;
  }
};


struct another_super_stream : basic_stream {};

int main()
{
  super_stream ss;

  basic_stream& bs = ss;

  std::vector<int> v;
  bs << v;

}


В краце хочеться, чтобы каждый стрим мог форматировать данные как ему хочеться. Но в момент, когда начинается форматирование у меня есть только ссылка на базовый стрим.

Понятно, что приведенный код работать не будет: в базом классе нет нужного operator <<.
Добавить его в базовый класс и сделат виртуальным тоже не получиться, так как он параметризован.

Есть ли возможность это как-то обойти? Или может есть стандартные приемы для подобных случаев?

Заранее спасибо.
Re: доступ к патомку через базовый класс
От: e-garin Россия  
Дата: 29.03.06 14:03
Оценка:
Здравствуйте, Nickolas, Вы писали:

N>Всем привет. Есть вот такой код:


N>
N>#include <iostream>
N>#include <vector>

N>struct basic_stream
N>{
N>  virtual std::ostream& operator << (int v) {}
N>};

N>struct super_stream : basic_stream
N>{

N>  template<typename T>
N>  std::ostream& operator << (T const &v)
N>  {
N>    std::cout << "operator << (T const &v)" << std::endl;
N>  }

N>  virtual std::ostream& operator << (int v)
N>  {
N>    std::cout << "operator << (int v)" << std::endl;
N>  }

N>  template<typename T>
N>  std::ostream& operator << (std::vector<T> const &v)
N>  {
N>    std::cout << "operator << (std::vector<T> const &v)" << std::endl;
N>  }
N>};


N>struct another_super_stream : basic_stream {};

N>int main()
N>{
N>  super_stream ss;

N>  basic_stream& bs = ss;

N>  std::vector<int> v;
N>  bs << v;

N>}
N>


N>В краце хочеться, чтобы каждый стрим мог форматировать данные как ему хочеться. Но в момент, когда начинается форматирование у меня есть только ссылка на базовый стрим.


N>Понятно, что приведенный код работать не будет: в базом классе нет нужного operator <<.

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

N>Есть ли возможность это как-то обойти? Или может есть стандартные приемы для подобных случаев?


Ну насколько я понимаю, через интерфейс базового класса можно вызвать только методы в нём (интерфейсе) определённые. Если хочется вызывать методы наследников, то приводи тип, используя dynamyc_cast.
А мне нравится жить :).
Re[2]: доступ к патомку через базовый класс
От: Nickolas Чехия  
Дата: 29.03.06 14:09
Оценка:
Здравствуйте, e-garin, Вы писали:


EG>Ну насколько я понимаю, через интерфейс базового класса можно вызвать только методы в нём (интерфейсе) определённые. Если хочется вызывать методы наследников, то приводи тип, используя dynamyc_cast.



Ну вот у меня есть два потомка-стрима в примере super_stream и another_super_stream. К какому из них приводить?
В момент начала форматирования тип неизвестен
Re: доступ к патомку через базовый класс
От: rg45 СССР  
Дата: 29.03.06 14:25
Оценка:
"Nickolas" <116@users.rsdn.ru> wrote in message news:1811985@news.rsdn.ru...
> Всем привет. Есть вот такой код:

Эта задача решалась бы, если бы можно было объявить basic_stream так:

struct basic_stream
{
  virtual std::ostream& operator << (int v);
  template<typename T>
  virtual std::ostream& operator << (std::vector<T> const &v);  //Так нельзя
};


Но, к сожалению (а может к счастью), шаблонные виртуальные функции не предусмотрены в С++ стандартом.
Поэтому в общем виде эта задача не решается, прийдется искать решение для более частных случаев.
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: доступ к патомку через базовый класс
От: Nickolas Чехия  
Дата: 29.03.06 14:43
Оценка:
Здравствуйте, rg45, Вы писали:


R>"Nickolas" <116@users.rsdn.ru> wrote in message news:1811985@news.rsdn.ru...

>> Всем привет. Есть вот такой код:

R>Эта задача решалась бы, если бы можно было объявить basic_stream так:


R>
R>struct basic_stream
R>{
R>  virtual std::ostream& operator << (int v);
R>  template<typename T>
R>  virtual std::ostream& operator << (std::vector<T> const &v);  //Так нельзя
R>};
R>


R>Но, к сожалению (а может к счастью), шаблонные виртуальные функции не предусмотрены в С++ стандартом.

R>Поэтому в общем виде эта задача не решается, прийдется искать решение для более частных случаев.

Угу, я про это писал, что так нельзя.

Можно конечно привлечь сюда RTTI:



template <typename T>
std::ostream& operator << (basic_stream &s), std::vector<T> const &v)
{
    super_stream *ss;
    another_super_stream *ass;

   if((ss=dynamic_cast<super_stream *>(&s)))
   {
     ..........      

   } else if ((ass=dynamic_cast<another_super_stream &>(s)))
   {
      ........
   } else
   {
      std::throw bad_cast();
   }
}



Но это мне не нравиться!

Хотелось бы другой вариант....
Re[3]: доступ к патомку через базовый класс
От: Nickolas Чехия  
Дата: 29.03.06 14:48
Оценка:
в предыдущем очепятка

вместо


} else if ((ass=dynamic_cast<another_super_stream &>(s)))



должно быть


} else if ((ass=dynamic_cast<another_super_stream *>(s)))
Re: доступ к патомку через базовый класс
От: zaufi Земля  
Дата: 29.03.06 15:06
Оценка:
довольно дурацкий подход с кучей проблем... попробуй пересмотреть концепт кардинально... например сделать классы formatterов способных выводить в стрим (любой, а не только cout) что тебе там требуеца...
в результате запись буит примерна такой:

  std::cout << super_formatter(int(10)) << another_formatter(MyMegaClass()) << templated_formatter<string>("some string")...


* форматилки получают в конструкторе то чего нада выводить (конструкторы при этом могут быть шаблонные)
* форматилки сами могут быть шаблонными
* все форматилки наследники интерфейса некой "абстрактной форматилки" имеющей спец функцию для вывода в стрим
* есь перегруженый оператор вывода абстрактной форматилки в стрим вызывающий указанную виртуальную функцию...

это все может дать мегагибкость...

однако я не телепат и более точные условия задачи не помешали бы... (вместа попытки решить твою конкретную проблему с парой классов)
Re[3]: доступ к патомку через базовый класс
От: Chorkov Россия  
Дата: 30.03.06 14:42
Оценка:
Здравствуйте, Nickolas, Вы писали:

N>Ну вот у меня есть два потомка-стрима в примере super_stream и another_super_stream. К какому из них приводить?

N>В момент начала форматирования тип неизвестен

Если функция, которую ты собираешься вызвать определена во всех классах — потомках, то, возможно, следует вынести ее в отдельный класса — интерфейс, от которого и наследовать super_stream и another_super_stream.
Re[2]: доступ к патомку через базовый класс
От: darkserj  
Дата: 30.03.06 17:38
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Nickolas, Вы писали:



N>>Есть ли возможность это как-то обойти? Или может есть стандартные приемы для подобных случаев?

А>Для начала надо вспомнить что параметризировать клиенский код можно не только средствами динамического полиморфизма но и на основе статического

N>>Понятно, что приведенный код работать не будет: в базом классе нет нужного operator <<.

N>>Добавить его в базовый класс и сделат виртуальным тоже не получиться, так как он параметризован.
А>Нам не нужен базовый класс, нам нужна полиморфная функция, написанная единожды и работающая с разными типами

N>>В краце хочеться, чтобы каждый стрим мог форматировать данные как ему хочеться.

А>Предлагаю рассмотреть возможное решение на основе CRTP (curiously recurrent template pattern)

А в какой момент позовется выделенный оператор? И для чего он вообще тут нужен?
А>#include <vector>

А>using namespace std;

А>template <typename T>
А>struct basic_stream
А>{
А>    template <typename U>    
А>    std::ostream& operator << (T v)
А>        {
А>            return static_cast<T&>(*this).operator<<(v);
А>        }
А>};


А>struct super_stream : basic_stream<super_stream>
А>{
А>  template<typename T>
А>  std::ostream& operator << (T const &v)
А>  {
А>    std::cout << "super_stream::operator << (T const &v)" << std::endl;
А>    return std::cout;
А>  }

А>  std::ostream& operator << (int v)
А>  {
А>    std::cout << "super_stream::operator << (int v)" << std::endl;
А>    return std::cout;
А>  }

А>  template<typename T>
А>  std::ostream& operator << (std::vector<T> const &v)
А>  {
А>    std::cout << "super_stream::operator << (std::vector<T> const &v)" << std::endl;
А>    return std::cout;
А>  }
А>};

А>struct another_super_stream : basic_stream<another_super_stream>
А>{
А>  template<typename T>
А>  std::ostream& operator << (T const &v)
А>  {
А>    std::cout << "another_super_stream::operator << (T const &v)" << std::endl;
А>    return std::cout;
А>  }

А>  std::ostream& operator << (int v)
А>  {
А>    std::cout << "another_super_stream::operator << (int v)" << std::endl;
А>    return std::cout;
А>  }

А>  std::ostream& operator << (double v)
А>  {
А>    std::cout << "another_super_stream::operator << (double v)" << std::endl;
А>    return std::cout;
А>  }
А>};

А>template <typename STREAM_T, typename VALUE_T>
А>void static_polymorphic_output(STREAM_T& stream, VALUE_T v)
А>{
А>    stream << v;
А>}

А>int main(int argc, char* argv[])
А>{
А>    super_stream            ss;
А>    another_super_stream    ass;
А>    std::vector<int>        v;

А>    static_polymorphic_output(ss,10);
А>    // output: super_stream::operator << (int v)
А>    static_polymorphic_output(ass,10);
А>    // output: another_super_stream::operator << (int v)
А>    static_polymorphic_output(ss,v);
А>    // output: super_stream::operator << (std::vector<T> const &v)
А>    static_polymorphic_output(ass,v);
А>    // output: another_super_stream::operator << (T const &v)
А>    static_polymorphic_output(ss,10.);
А>    // output: super_stream::operator << (T const &v)
А>    static_polymorphic_output(ass,10.);
А>    // output: another_super_stream::operator << (double v)

А>    return 0;
А>}
Re[3]: доступ к патомку через базовый класс
От: Аноним  
Дата: 31.03.06 09:21
Оценка:
Здравствуйте, darkserj, Вы писали:


D>А в какой момент позовется выделенный оператор? И для чего он вообще тут нужен?

D>
А>>#include <vector>

А>>using namespace std;

А>>template <typename T>
А>>struct basic_stream
А>>{
А>>    template <typename U>    
А>>    std::ostream& operator << (T v)
А>>        {
А>>            return static_cast<T&>(*this).operator<<(v);
А>>        }
А>>};
D>


Никогда!. Ваша правда, приведенный пример это не демонстрирует.
Для начала исправим ошибку

template <typename T>
struct basic_stream
{
    template <typename U>    
    std::ostream& operator << (U v) // must be U instead of T
        {
            return static_cast<T&>(*this).operator<<(v);
        }
};


Дополним код клиента
int main(int argc, char* argv[])
{
    super_stream            ss;
    another_super_stream    ass;
    std::vector<int>        v;

    // ... 

    basic_stream<super_stream>&         bs_ss = ss;
    basic_stream<another_super_stream>& bs_ass = ass;
    static_polymorphic_output(bs_ss,10);
    // output: super_stream::operator << (int v)
    static_polymorphic_output(bs_ass,10);
    // output: another_super_stream::operator << (int v)

    return 0;
}


Но все это, ИМХО, надумано и с точки зрения применимости практически равно нулю.
Использование CRTP здесь явно ни к месту, просто избавляемся от basic_stream<...> и в итоге имеем

#include <vector>

using namespace std;


struct super_stream
{
  template<typename T>
  std::ostream& operator << (T const &v)
  {
    std::cout << "super_stream::operator << (T const &v)" << std::endl;
    return std::cout;
  }

  std::ostream& operator << (int v)
  {
    std::cout << "super_stream::operator << (int v)" << std::endl;
    return std::cout;
  }

  template<typename T>
  std::ostream& operator << (std::vector<T> const &v)
  {
    std::cout << "super_stream::operator << (std::vector<T> const &v)" << std::endl;
    return std::cout;
  }
};

struct another_super_stream
{
  template<typename T>
  std::ostream& operator << (T const &v)
  {
    std::cout << "another_super_stream::operator << (T const &v)" << std::endl;
    return std::cout;
  }

  std::ostream& operator << (int v)
  {
    std::cout << "another_super_stream::operator << (int v)" << std::endl;
    return std::cout;
  }

  std::ostream& operator << (double v)
  {
    std::cout << "another_super_stream::operator << (double v)" << std::endl;
    return std::cout;
  }
};

template <typename STREAM_T, typename VALUE_T>
void static_polymorphic_output(STREAM_T& stream, VALUE_T v)
{
    stream << v;
}

int main(int argc, char* argv[])
{
    super_stream            ss;
    another_super_stream    ass;
    std::vector<int>        v;

    static_polymorphic_output(ss,10);
    // output: super_stream::operator << (int v)
    static_polymorphic_output(ass,10);
    // output: another_super_stream::operator << (int v)
    static_polymorphic_output(ss,v);
    // output: super_stream::operator << (std::vector<T> const &v)
    static_polymorphic_output(ass,v);
    // output: another_super_stream::operator << (T const &v)
    static_polymorphic_output(ss,10.);
    // output: super_stream::operator << (T const &v)
    static_polymorphic_output(ass,10.);
    // output: another_super_stream::operator << (double v)

    return 0;
}


Спасибо за коммент, хоть кто-то разобрался до конца
Re[4]: доступ к патомку через базовый класс
От: Nickolas Чехия  
Дата: 31.03.06 12:09
Оценка:
Здравствуйте, Аноним, Вы писали:


А>Спасибо за коммент, хоть кто-то разобрался до конца


Я не то, чтобы не разобрался в Вашем примере, просто это решение мне не совсем подходит.

template <typename T>
struct basic_stream
{
    template <typename U>    
    std::ostream& operator << (U v) // must be U instead of T
        {
            return static_cast<T&>(*this).operator<<(v);
        }
};


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

Но всеравно огромное Вам спасибо — Ваше решение навело меня на некоторые полезные мысли
Re[2]: доступ к патомку через базовый класс
От: Nickolas Чехия  
Дата: 31.03.06 16:08
Оценка:
Здравствуйте, bolshik, Вы писали:


B>Страуструп в таком случае предлагает следующий подход:


Спасибо, именно так я и решил свою проблему
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.