Шаблоны виртуальных функций. В чем проблемма?
От: dip_2000 Россия  
Дата: 05.09.07 11:05
Оценка:
Еще один вопрос из серии : поиск не работает, если что не ругайтесь

Вот есть виртуальные функции, есть возможность создавать перегруженные виртуальные функции.
В чем проблемма(для компилятора и для стандарта) разрешить использование шаблонов виртуальных функций ?
PS Кажется кто-то не очень давно постил пример "обхода" этого запрета. Может быть повторите ?


Спасибо.
Re: шаблонные виртуальные
От: Erop Россия  
Дата: 05.09.07 11:16
Оценка:
Здравствуйте, dip_2000, Вы писали:

_>Вот есть виртуальные функции, есть возможность создавать перегруженные виртуальные функции.

_>В чем проблемма(для компилятора и для стандарта) разрешить использование шаблонов виртуальных функций ?
_>PS Кажется кто-то не очень давно постил пример "обхода" этого запрета. Может быть повторите ?
_>

Проблема в том, что не ясно что хочешь

Общая идея такая, что когда функция вертуальная, то клиентсикй код может не знать о том, какие реализации были на самом деле реализованы. А сам код перегруженной функции может не знать о том, какие контексты используют его вызов. Типа всё хорошо. Можно вообще в любом порядке реализовывать.

А вот если придумать "шаблонную виртуальную" функцию, то получится, что клиент должен как-то сообщить в реализацию контекст вызова. В этмо месте возникает противоречие. Если ты согласен чем-то поступииться, то можно как-то реализовать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: шаблонные виртуальные
От: dip_2000 Россия  
Дата: 05.09.07 11:23
Оценка:
E>Проблема в том, что не ясно что хочешь

А я немного поконкретнее вопрос поставлю:
Почему я могу так
class SomeClassWithAllOperator<<
{
virtual std::ofstream& putToStream(std::ofstream& stream)
{
return stream << (*this);            
}
virtual SOCKET& putToStream(SOCKET& stream)
{
    return stream << (*this);            
}
};//end


и не могу вот так
class SomeClassWithOperator<<
{
template<typename streamT>
virtual streamT& putToStream(streamT& stream)
{
return stream << (*this);            
}
};//end

?
Re[3]: шаблонные виртуальные
От: Erop Россия  
Дата: 05.09.07 12:20
Оценка: 1 (1) -1
Здравствуйте, dip_2000, Вы писали:


_>и не могу вот так

_>
_>class SomeClassWithOperator<<
_>{
_>template<typename streamT>
_>virtual streamT& putToStream(streamT& stream)
_>{
_>return stream << (*this);            
_>}
_>};//end
_>

_>?

Ровно пготому же.
Вот представь себе что ты реализуешь себе наследника SomeClassWithOperator, в котором определяешь putToStream для каких-то там типов, потом компилируешь это всё, засовываешь в плагин и поставялешь куда-то пользователю.
Потом ты приделываешь ещё другой плагин, в котором появляется новый тип потока. При этом права на наследника принадлежат тебе и ты никому не кажешь сорцы, а права на новый поток принадлежат третей фирме и она никому не кажется сорцы. Кто скомпилирует код твоего наследника для этого потока? И где он возьмёт узнает этот код?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: шаблонные виртуальные
От: Bell Россия  
Дата: 05.09.07 12:21
Оценка: 2 (2)
Здравствуйте, dip_2000, Вы писали:


E>>Проблема в том, что не ясно что хочешь


_>А я немного поконкретнее вопрос поставлю:


Вот и давай посмотим с конкретной стороны. Таблица виртуальных функций — популярный способ реализации механизма позднего связывания. При такой реализации каждой виртуальной функции соответствует запись в таблице.
Теперь о шаблонах: для каждого типа при инстанциировании шаблона создается своя уникальная функция.
Внимание вопрос: каким образом должна заполняться таблица виртуальных функций в этом случае?
Любите книгу — источник знаний (с) М.Горький
Re[4]: шаблонные виртуальные
От: Erop Россия  
Дата: 05.09.07 12:29
Оценка:
Здравствуйте, Bell, Вы писали:

B>Теперь о шаблонах: для каждого типа при инстанциировании шаблона создается своя уникальная функция.

B>Внимание вопрос: каким образом должна заполняться таблица виртуальных функций в этом случае?
1) Например в соответсвующей ячейке может стоят map из типа апарметров в реализацию...
2) таблица виртуальных функций -- не догма...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Sergey! А что не так-то?
От: Erop Россия  
Дата: 05.09.07 12:32
Оценка:
Здравствуйте, Erop, Вы писали:

E>И где он возьмёт узнает этот код?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: to Егор & Bell
От: dip_2000 Россия  
Дата: 05.09.07 12:33
Оценка:
Сдаюсь... вы правы.
Но нет ли возможности это как то обойти ? Для данного конкретного случая, когда все типы известны на стадии компиляци, и единственная цель — не плодить кода похожего друг на друга как 2 капли воды?

PS Ну кроме макросов.
Re[5]: шаблонные виртуальные
От: Bell Россия  
Дата: 05.09.07 12:46
Оценка:
Здравствуйте, Erop, Вы писали:

E>1) Например в соответсвующей ячейке может стоят map из типа апарметров в реализацию...

Да, наверное. Устроят ли всех такие затраты при вызове виртуальной функции — не уверен...
E>2) таблица виртуальных функций -- не догма...
Я этого и не говорил
Любите книгу — источник знаний (с) М.Горький
Re[4]: to Егор & Bell
От: Bell Россия  
Дата: 05.09.07 12:51
Оценка:
Здравствуйте, dip_2000, Вы писали:

_> Сдаюсь... вы правы.

_>Но нет ли возможности это как то обойти ? Для данного конкретного случая, когда все типы известны на стадии компиляци, и единственная цель — не плодить кода похожего друг на друга как 2 капли воды?
_>
_>PS Ну кроме макросов.


class SomeClassWithOperator<<
{
   template<typename streamT>
   streamT& putToStreamTempl(streamT& stream)
   {
      return stream << (*this);            
   }

   virtual std::ofstream& putToStream(std::ofstream& stream)
   {
      return putToStreamTempl(stream);            
   }
   virtual SOCKET& putToStream(SOCKET& stream)
   {
      return putToStreamTempl(stream);            
   }
};
Любите книгу — источник знаний (с) М.Горький
Re[5]: to Егор & Bell
От: dip_2000 Россия  
Дата: 05.09.07 12:54
Оценка:
Здравствуйте, Bell, Вы писали:
B>
B>class SomeClassWithOperator<<
B>{
B>   template<typename streamT>
B>   streamT& putToStreamTempl(streamT& stream)
B>   {
B>      return stream << (*this);            
B>   }

B>   virtual std::ofstream& putToStream(std::ofstream& stream)
B>   {
B>      return putToStreamTempl(stream);            
B>   }
B>   virtual SOCKET& putToStream(SOCKET& stream)
B>   {
B>      return putToStreamTempl(stream);            
B>   }
B>};
B>

Re[6]: шаблонные виртуальные
От: Erop Россия  
Дата: 05.09.07 13:00
Оценка:
Здравствуйте, Bell, Вы писали:

E>>1) Например в соответсвующей ячейке может стоят map из типа апарметров в реализацию...

B>Да, наверное. Устроят ли всех такие затраты при вызове виртуальной функции — не уверен...
Ну map может быть очень быстрым, таки. индекс контекста можно генерироватьодин раз, при инициализации программы
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: шаблонные виртуальные
От: Кодт Россия  
Дата: 05.09.07 13:14
Оценка:
Здравствуйте, dip_2000, Вы писали:

_>А я немного поконкретнее вопрос поставлю:

_>Почему я могу так
_>class SomeClassWithAllOperator<<

Не можешь. Что за странное имя у класса?

На самом деле, попробуй представить, как могло бы быть реализовано то, что ты пожелал.
Вот у тебя есть базовый класс с шаблоном виртуальной функции. И есть класс-наследник.
1) Как наследник перекроет шаблон — полностью или выборочно — так, что по указателю на базу мы сможем вызвать перекрытую функцию?
2) Пусть
— мы скомпилировали наследника в единице трансляции x.cpp
— в единице трансляции y.cpp завели код, скрещивающий базу с типом Y (про наследника здесь ничего не известно)
— в единице трансляции z.cpp создали экземпляр наследника (про тип Y здесь ничего не известно) и передали как указатель на базу в функцию из y.cpp

В принципе такая задача решаема. Но не средствами компилятора С++, а ручками.

Например, в Haskell или O'Haskell в шаблон функции неявно передаётся комплект примитивных функций над типом аргумента. Поэтому шаблон не является шаблоном в С++ном смысле, это скорее паттерн "шаблонный метод" (Template Method).

Так и здесь можно
struct IFormalOStream
{
    virtual void feed(char) = 0;
    virtual void feed(int) = 0;
    virtual void feed(string) = 0;
    virtual void feed(iomanip) = 0;
};

// болванка, превращающая любой поток с оператором << в формальный поток
template<class Stream>
struct FormalOStream : IFormalOStream
{
    Stream& m_ost;
    FormalOStream(Stream& ost) : m_ost(ost) {}
    void feed(char c) { m_ost << c; }
    void feed(int n) { m_ost << n; }
    void feed(string s) { m_ost << s; }
    void feed(iomanip m) { m_ost << m; }
};


class SomeClass
{
    int x, y, z;
public:
    virtual void pass(IFormalOStream& ost) const
    {
        ost.feed(x); ost.feed(y); ost.feed(z);
    }
};

class SomeDerivedClass : public SomeClass
{
    char c; string s;
    SomeClass aggregate;
public:
    void pass(IFormalOStream& ost) const
    {
        SomeClass::pass(ost);
        ost.feed(c); ost.feed(s);
        aggregate.pass(ost);
    }
};

void foo(SomeClass const& obj)
{
    SOCKET sck;
    obj.pass(FormalOStream<SOCKET>(sck));
    
    obj.pass(FormalOStream<ostream>(cout));
}

int main()
{
    foo(SomeDerivedClass());
}

Я не стал связываться с инфиксными операторами, чтобы не вводить путаницу. Хотя прикрутить их несложно.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: Шаблоны виртуальных функций. В чем проблемма?
От: Erop Россия  
Дата: 05.09.07 13:30
Оценка:
Здравствуйте, dip_2000, Вы писали:

_>PS Кажется кто-то не очень давно постил пример "обхода" этого запрета. Может быть повторите ?

Повторять не буду, так как это было очень сложно. Ты можешь попробовтаь решить свою проблему проще. Например так:
class AbstractStream {
public:
   virtual AbstractStream& operator << ( int ) = 0;
   virtual AbstractStream& operator << ( const char* ) = 0;
   // и т. д.

};

template<class TRealStream>
class CStreamProxy : public AbstractStream {
public:
    CStreamProxy( TRealStream& theStream_ ) : theStream( theStream_ ) {}
   
   virtual AbstractStream& operator << ( int v ) { return doIt( v ); }
   virtual AbstractStream& operator << ( const char* ) { return doIt( v ); }
   // и т. д.

private:
    TRealStream& theStream;
    template<typename T> AbstractStream& doIt( T v ) 
    {
        theStream << v;
        return *this;
    }
};



Ну а теперь, легко можешь писать себе:
class CMyClassBase {
public:
    // шаблонная виртуальная функция
    template<typename TStream> void DumpIt( TStream& dst ) 
    { 
        CStreamProxy<TStream> proxy( dst ); 
        doDumpIt( proxy ); 
    }

protected:
    virtual void doDumpIt( AbstractStream& dst ) = 0;
}


Ну а в наследниках смело перекрываешь doDumpIt да и пишешь как хочешь


Если такое определение CStreamProxy кажется тебе слишком громоздким, можешь немного "упростить" это дело при помощи boost::mpl или какой-нибудь конструкции из макросов.

Например такой:
#define ABSTRACT_STREAM_METHOD_IMPL( ResultType, MethodBody, OutputType ) \
    virtual ResultType operator << ( OutputType v ) MethodBody

#define ABSTRACT_STREAM_VIRTUAL_METHODS_DECLARATOR( ResultTypee, MethodBody ) \
    ABSTRACT_STREAM_METHOD_IMPL( ResultTypee, MethodBody, int ) \
    ABSTRACT_STREAM_METHOD_IMPL( ResultTypee, MethodBody, const char* ) \
    // и т. д.

class AbstractStream {
public:
    ABSTRACT_STREAM_VIRTUAL_METHODS_DECLARATOR( AbstractStream&, = 0; )
};

template<class TRealStream>
class CStreamProxy : public AbstractStream {
public:
    CStreamProxy( TRealStream& theStream_ ) : theStream( theStream_ ) {}
    ABSTRACT_STREAM_VIRTUAL_METHODS_DECLARATOR( AbstractStream&, { return doIt( v ); } )

private:
    TRealStream& theStream;
    template<typename T> AbstractStream& doIt( T v ) 
    {
        theStream << v;
        return *this;
    }
};



_>Спасибо.
Лучше галочку поставь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Sergey! А что не так-то?
От: Sergey Россия  
Дата: 05.09.07 14:21
Оценка:
> E>И где он возьмёт узнает этот код?

Нигде не возмет. Но виртуальность тут не при чем и аргументация мимо кассы. В случае обычной невиртуальной шаблонной функции будут ровно те же проблемы. И собственно виртуальные шаблонные функции были бы применимы (если б были бы реализованы) в таких же условиях, где и просто шаблонные. Да и вообще, авторы стандарта вряд ли думали насчет поддержки плагинов.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: Sergey! А что не так-то?
От: Erop Россия  
Дата: 05.09.07 14:25
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Нигде не возмет. Но виртуальность тут не при чем и аргументация мимо кассы. В случае обычной невиртуальной шаблонной функции будут ровно те же проблемы. И собственно виртуальные шаблонные функции были бы применимы (если б были бы реализованы) в таких же условиях, где и просто шаблонные. Да и вообще, авторы стандарта вряд ли думали насчет поддержки плагинов.


Я сначала объяснил более абстрактно что мешает. Потом более конкретно. О раздельной компиляции авторы стандарта наверное думали? Ну так вот шаблонные виртуальные методы противоречат принципу раздельнйо компиляции.
Так верно?

Просто так не понятно. На примере, ИМХО, понятнее.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: to Егор & Bell
От: jazzer Россия Skype: enerjazzer
Дата: 05.09.07 15:21
Оценка:
Здравствуйте, dip_2000, Вы писали:

_> Сдаюсь... вы правы.

_>Но нет ли возможности это как то обойти ? Для данного конкретного случая, когда все типы известны на стадии компиляци, и единственная цель — не плодить кода похожего друг на друга как 2 капли воды?
_>
_>PS Ну кроме макросов.

Можешь конкретный пример дать? А то по предыдущему примеру (http://rsdn.ru/forum/message/2645828.1.aspx
Автор: dip_2000
Дата: 05.09.07
) ну ничего не понятно.

PS А что, против макросов у нас религиозное предубеждение?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Sergey! А что не так-то?
От: Sergey Россия  
Дата: 05.09.07 15:43
Оценка: -1
> S>Нигде не возмет. Но виртуальность тут не при чем и аргументация мимо кассы. В случае обычной невиртуальной шаблонной функции будут ровно те же проблемы. И собственно виртуальные шаблонные функции были бы применимы (если б были бы реализованы) в таких же условиях, где и просто шаблонные. Да и вообще, авторы стандарта вряд ли думали насчет поддержки плагинов.
>
> Я сначала объяснил более абстрактно что мешает. Потом более конкретно. О раздельной компиляции авторы стандарта наверное думали? Ну так вот шаблонные виртуальные методы противоречат принципу раздельнйо компиляции.

Вот конкретика насчет плагинов — она вообще не в тему. Опять же, обычные шаблонные методы (равно как и просто inline) тоже противоречат принципу раздельной компиляции (если не принимать в расчет экзотику типа экспорта шаблонов).
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[8]: Sergey! А что не так-то?
От: Erop Россия  
Дата: 05.09.07 15:47
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Вот конкретика насчет плагинов — она вообще не в тему. Опять же, обычные шаблонные методы (равно как и просто inline) тоже противоречат принципу раздельной компиляции (если не принимать в расчет экзотику типа экспорта шаблонов).


Правда? А чего нет в C++ раздельной компиляции или шаблонов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Sergey! А что не так-то?
От: Sergey Россия  
Дата: 05.09.07 15:53
Оценка:
> S>Вот конкретика насчет плагинов — она вообще не в тему. Опять же, обычные шаблонные методы (равно как и просто inline) тоже противоречат принципу раздельной компиляции (если не принимать в расчет экзотику типа экспорта шаблонов).
>
> Правда? А чего нет в C++ раздельной компиляции или шаблонов?

Раздельной компиляции шаблонов, разумеется. На практике нет — в стандарте она предусмотрена. Пока предусмотрена
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.