| 
			| 
					
						| baldr | 
								|  | «  : 13-11-2004 08:59 »  |  | 
 
 Есть у меня два класса: template <class C>class Synchronizer
 {
 private:
 Synchronizer(); // Hidden constructor to realize Singleton pattern
 static Synchronizer<C> *_self;
 public:
 static Synchronizer<C> *Instance();
 };
 
 class BehaviourController
 {
 public:
 BehaviourController();
 private:
 Synchronizer <BehaviourController>*Sync;
 };
И, соответственно, реализация: template <class C>Synchronizer<C>::Synchronizer()
 {
 //  stuff
 }
 
 template <class C>
 Synchronizer<C> *Synchronizer<C>::Instance()
 {
 if(!_self)
 {
 _self = new Synchronizer();
 }
 return _self;
 }
Тут все нормально, вроде? А если делаем вот так: BehaviourController::BehaviourController(){
 Sync=Synchronizer<BehaviourController>::Instance();
 }
То компилятор верещит вот так: BehaviourController.obj : error LNK2001: unresolved external symbol "public: static class Synchronizer<class BehaviourController> * __cdecl Synchronizer<class BehaviourController>::Instance(void)" (?Instance@?$Synchronizer@VBehaviourController@@@@SAPAV1@XZ) Вопрос: Что я делаю не так? Я хотел реализовать класс с шаблоном (дальше с ним идет работа) на основе паттерна Singleton. Пока не было шаблона, все было нормально.  :? |  
						| 
								|  |  
								| « Последнее редактирование: 29-09-2009 07:13 от Алексей1153++ » |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| Pu 
								Большой босс    Offline 
								78
								
								
								
								
								
							 | 
								|  | « Ответ #1 : 13-11-2004 12:14 »  |  | 
 
 baldr, я не вижу инициализации статик указателя  static Synchronizer<C> *_self;
 в реализации надо бы добавить чтото вроде
 Synchronizer *Synchronizer::_self = 0;
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.(с) Артур Джонс
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #2 : 13-11-2004 13:58 »  |  | 
 
 Да, сорри, это есть. Забыл указать. Но проблема не в этом. |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| Pu 
								Большой босс    Offline 
								78
								
								
								
								
								
							 | 
								|  | « Ответ #3 : 13-11-2004 14:30 »  |  | 
 
 baldr, гут , ща посмотрю ышо    |  
						| 
								|  |  
								|  |  Записан | 
 
 Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.(с) Артур Джонс
 |  |  | 
	| 
			| 
					
						| Serega 
								Гость
 | 
								|  | « Ответ #4 : 13-11-2004 15:45 »  |  | 
 
 Где у тебя находится реализация ? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #5 : 15-11-2004 07:31 »  |  | 
 
 Описание каждого класса находится в разных файлах. Реализация - тоже.Проблема исчезает, если делать без шаблонов... :new_shot:
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| dedOK 
								Гость
 | 
								|  | « Ответ #6 : 15-11-2004 09:05 »  |  | 
 
 Чтобы использовать шаблон функции или класса в некотором модуле, в этом модуле должно иметься определение функции или класса и всех его элементов.  // "C.h"template <typename T>
 class C {
 void f();
 ...
 };
 template <typename T>
 void C<T>::f() {
 ...
 }
 
#include "C.h"C<int> a;
 ...
 
Второй вариант - явное инстанционирование используемых экземпляров шаблонов в модуле с определениями. // "C.h"template <typename T>
 class C {
 void f();
 ...
 };
 
// "C.cpp"#include "C.h"
 template <typename T>
 void C<T>::f() {
 ...
 }
 
 template<> class C<int>;
 
#include "C.h"C<int> a;
 ...
 
 |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:34 от Алексей1153++ » |  Записан | 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #7 : 15-11-2004 14:38 »  |  | 
 
 dedOK, по-моему, меня не поняли.  :new_mpr:Я знаю что такое шаблон.
 По-моему, у тебя написано то же самое, что и у меня. :l_smile:
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| dedOK 
								Гость
 | 
								|  | « Ответ #8 : 16-11-2004 18:23 »  |  | 
 
 Не знаю каким ты компилятором пользуешься, но у меня в билдере все скомпилировалось и запустилось без проблем: template <class C>class Synchronizer {
 private:
 Synchronizer();
 static Synchronizer<C> *_self;
 public:
 static Synchronizer<C> *Instance();
 };
 
 template <class C> Synchronizer<C>* Synchronizer<C>::_self;
 
 template <class C>
 Synchronizer<C>::Synchronizer() { /* stuff */ }
 
 template <class C>
 Synchronizer<C> *Synchronizer<C>::Instance()
 {
 if(!_self)
 {
 _self = new Synchronizer();
 }
 return _self;
 }
 
 class BehaviourController
 {
 public:
 BehaviourController();
 private:
 Synchronizer <BehaviourController>*Sync;
 };
 
 BehaviourController::BehaviourController()
 {
 Sync=Synchronizer<BehaviourController>::Instance();
 }
 
 int main(int argc, char* argv[])
 {
 BehaviourController a, b;
 return 0;
 }
 
 |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:38 от Алексей1153++ » |  Записан | 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #9 : 17-11-2004 07:41 »  |  | 
 
 dedOK, и в самом деле...      У меня MSVC все нормально взял если в одном файле. А попробуй сделать описания классов в отдельных .h-файлах, реализацию - в отдельных .cpp-файлах?  Ведь линкер поэтому и орет, что не находит метод... У меня, вроде, все файлы включаются нормально...  :? |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| npak | 
								|  | « Ответ #10 : 17-11-2004 11:42 »  |  | 
 
 baldr, методы для шаблонного класса должны быть реализованы в той же единице компиляции, где они используются.
 Пусть ты вынес тела методов шаблонного класса в отдельный файл, скажем tmpl_impl.c
 Тогда ты можешь использовать эти методы либо в файле tmpl_impl.c, либо надо явным образом включать tmpl_impl.c, то есть перед первым использованием шаблонного класса надо вставить
 #include "tmpl_impl.c"
 
 Дело в том, что методы шаблонного класса не являются функциями.  При инстанциации шаблона компилятор подставляет аргументы шаблона и генерирует фактические методы.  Поэтому компилятору надо знать тела шаблонных методов, чтобы из них сгенерировать фактические методы.
 
 Линкер тут ни причём.  До него дело даже не доходит.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #11 : 17-11-2004 13:55 »  |  | 
 
 npak, компилятор все проходит нормально. А кричит как раз линкер.И про то, что ты говоришь я первый раз слышу. Собственно, какая компилятору разница - описание класса есть и реализация есть? В реализации есть include для описания.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #12 :  17-11-2004 16:01 »   |  | 
 
 Как это ни странно, но npak  прав. Правда, я не понял почему.  :oops:  Соответственно, npak  получает +1 и выходит в следующий тур.    |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| npak | 
								|  | « Ответ #13 : 17-11-2004 16:14 »  |  | 
 
 baldr, сорри, немного отстал от жизни про инстанциацию шаблонов.  Ругается действительно линкер, но причина именна та, про которую я писал -- компилятор не может сгененрировать метод для инстанса. Когда компилятор доходит до строки  Sync=Synchronizer<BehaviourController>::Instance();он пытается сгенерировать функцию с именем "?Instance@?$Synchronizer@VBehaviourController@@@@SAPAV1@XZ".  Но ему это не удаётся (почему -- см. далее).  Компилятор вставляет ссылку на функцию с этим именем и продолжает обработку файла.  При сборке приложения линкер ругается, так как ни в одном объектнике функция с таким именем не обнаружена В объектнике с "реализацией" шаблонных методов нет такой функции, так как в соответствующем исходнике не используется Synchronizer<BehaviourController>::Instance(). В объектнике с реализацией конструктора для BehaviorController нет функции, так как компилятор не смог создать тело метода. как происходит инстанциация метода (условно говоря) -- компилятор берёт тело шаблонного метода (текст!) и заменяет вхождения параметра шаблона на аргумент шаблона.  То есть должен строиться метод (BehaviorController_Synchronizer_instance -- внутреннее сгенерированное имя класса-инстанса): BehaviorController_Synchronizer_instance *BehaviorController_Synchronizer_instance::Instance() {
 if(!_self)
 {
 _self = new BehaviorController_Synchronizer_instance();
 }
 return _self;
 }
Почему не может создать тело метода? Потому что не из чего.  При компиляции файла с BehaviorController нет доступа к тексту файла с телами шаблонных методов, поэтому нет синтаксического материала для сборки тела метода инстанса. |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:43 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| dedOK 
								Гость
 | 
								|  | « Ответ #14 : 17-11-2004 21:28 »  |  | 
 
 Поэтому компилятору надо знать тела шаблонных методов, чтобы из них сгенерировать фактические методы.
 
 Как это ни странно, но npak прав. Правда, я не понял почему
 
 Меня, наверно не поняли.  :? Именно об этом я и писал первый раз. Постараюсь пояснить. При разработке шаблонов используются три модели: (1) модель включения (2) модель явного инстанционирования (3) модель разделения (или экспорта) (1) - создается "заголовочный файл", содержащий все объявления и определения классов и их функций. В том числе и невстариваемых (чего не делают для обычных функций). Далее, этот заголовок включается в тот модуль, где шаблон используется. В качестве примера можно посмотреть любой STL-заголовок. (2) Все делается как с обычными модулями. Но в модуль, где присутствуют все определения, вносят команды явного инстанционирования тех экземпляров шаблона, которые используются во всем проекте. (3) Все как с обычными модулями. При этом все определения классов и невстраеваемых функций помечаются ключевым словом export. Это есть в стандарте. Однако export сейчас большинство компиляторов не поддерживают. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #15 : 25-11-2004 16:45 »  |  | 
 
 Опять линкеру что-то не нравится.     Достал он меня... Вот что есть: //file Synchronizer.htemplate <class C>
 class Synchronizer
 {
 private:
 Synchronizer(); // Hiddec constructor to realize Singleton pattern
 static Synchronizer<C> *_self;
 public:
 static Synchronizer<C> *Instance() { if(!_self) _self = new Synchronizer(); return _self; }
 BOOL SetReportFunc(int (C::*RF)(long tick, SHORT* inputValArr));
 private:
 static int (C::*reportFunc)(long tick, SHORT* inputValArr);
 };
 #include "Synchronizer.cpp"
//file Synchronizer.cpptemplate <class C>
 Synchronizer<C>::Synchronizer()  { /*stuff*/ }
 
 template <class C>
 BOOL Synchronizer<C>::SetReportFunc(int (C::*RF)(long tick, SHORT* inputValArr))
 {
 if (RF=NULL) return FALSE;
 reportFunc=RF;
 return TRUE;
 }
 
 template <class C> Synchronizer<C> *Synchronizer<C>::_self=NULL;
 template <class C> int Synchronizer<C>::*reportFunc(long tick, SHORT* inputValArr)=NULL;
//file BehaviourController.h#include "Synchronizer.h"
 class BehaviourController
 {
 public:
 BehaviourController();
 private:
 Synchronizer<BehaviourController> *Sync;
 };
//file BehaviourController.cpp#include "stdafx.h"
 #include "BehaviourController.h"
 BehaviourController::BehaviourController()
 {
 Sync=Synchronizer<BehaviourController>::Instance();
 Sync->SetReportFunc(GetReport);
 }
 
Линкер кричит: BehaviourController.obj : error LNK2001: unresolved external symbol "private: static int (__thiscall BehaviourController::* Synchronizer<class BehaviourController>::reportFunc)(long,short *)" (?reportFunc@?$Synchronizer@VBehaviourController@@@@0P8BehaviourController@@AEHJPAF@ZQ2@) Сорри за большой кусок кода - зато все объяснил. Так вот. Линкеру не нравится описанная переменная-указатель на функцию reportFunc. Вопрос: правильно ли я ее описал в последней строке файла Synchronizer.cpp ? Попытку вставить все в один файл тут можно уже не предлагать - пробовал. Не работает.   |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:46 от Алексей1153++ » |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| dedOK 
								Гость
 | 
								|  | « Ответ #16 : 26-11-2004 05:27 »  |  | 
 
 По-моему дело в том, что template <class C> int Synchronizer<C>::*reportFunc(long tick, SHORT* inputValArr)=NULL;
выглядит как указатель на функцию-элемент Synchronizer<C>. А как указать что это указатель на функцию-элемент C и при этом статический элемент Synchronizer<C>? У меня слинковался такой код: template <class C>class Synchronizer
 {
 ...
 public:
 typedef int (C::*ReportFunc)(long tick, SHORT* inputValArr);
 ...
 BOOL SetReportFunc(ReportFunc rF);
 private:
 static ReportFunc reportFunc;
 };
 template <class C> Synchronizer<C>::ReportFunc Synchronizer<C>::reportFunc = NULL;
 
 |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:48 от Алексей1153++ » |  Записан | 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #17 : 26-11-2004 06:27 »  |  | 
 
 dedOK, гранмерси!!!Етить ее растак, но она слинковалась!
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #18 : 26-11-2004 08:06 »  |  | 
 
 Блин. Но как тогда ее вызвать?? int outVal=reportFunc(counter, wData);Так не прокатывает. error C2064: term does not evaluate to a function |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:50 от Алексей1153++ » |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| npak | 
								|  | « Ответ #19 : 26-11-2004 08:51 »  |  | 
 
 baldr, reportFunc возвращает указатель на метод.  Для вызова необходимо подставить объект класса C (не проверял) C objC;int   outVal=objC.*reportFunc(counter, wData);
 |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:51 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #20 : 26-11-2004 10:18 »  |  | 
 
 Делаю так: outVal=Parent->*reportFunc(counter, wData);Ничего. Та же ошибка линкера. Parent - Это C* Parent; |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:52 от Алексей1153++ » |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| npak | 
								|  | « Ответ #21 : 26-11-2004 12:59 »  |  | 
 
 baldr, это ошибка генерится компилятором Дело в том, что приоритет оператора "вызов функции" выше, чем оператора "Pointer to member", поэтому вызов функции по указателю надо оборачивать в скобки. outVal=(Parent->*reportFunc)(counter, wData); |  
						| 
								|  |  
								| « Последнее редактирование: 02-12-2007 17:53 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| baldr | 
								|  | « Ответ #22 : 26-11-2004 13:10 »  |  | 
 
 npak, отлично. Все работает.    |  
						| 
								|  |  
								|  |  Записан | 
 
 Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #23 : 29-01-2009 19:07 »  |  | 
 
 а вот такой вопрос скажем, в итоге что хочется получить (неважно, зачем, важно - удобно): class Parent{
 virtual Parent* NEW()=0;
 virtual void DELETE()=0;
 
 void F2()
 {
 Parent* pX=0;
 pX=pX->NEW();
 ...
 pX->=DELETE();
 };
 };
 
 class Child1:Parent
 {
 virtual Parent* NEW()
 {
 return new Child1;
 }
 
 virtual void DELETE()
 {
 delete (Child1*)this;
 }
 };
 
 class Child2:Parent
 {
 virtual Parent* NEW()
 {
 return new Child2;
 }
 
 virtual void DELETE()
 {
 delete (Child2*)this;
 }
 };
 
видим, что код детёв одинаков, за исключением имени типа дитя. Допустим, делаем через макрос class Parent{
 virtual Parent* NEW()=0;
 virtual void DELETE()=0;
 
 void F2()
 {
 Parent* pX=NEW();
 ...
 pX->=DELETE();
 };
 };
 
 #define Parent_new_delete(class_type) \
 virtual Parent* NEW()\
 {\
 return new (class_type);\
 }\
 \
 virtual void DELETE()\
 {\
 delete ((class_type)*)this;\
 }
 
 class Child1:Parent
 {
 Parent_new_delete(Child1)
 };
 
 class Child2:Parent
 {
 Parent_new_delete(Child2)
 };
 
 //пример вызова
 
 Child2 A;
 A.F2();
 
уже красивее выглядит. Но макрос не хотелось бы так оставлять. И вот вопрос: можно ли вместо данного макроса применить некий шаблон функции ? Насколько я понял, для этого потребуется шаблон класса, но мне его тут нафиг не надо... Как лучше поступить ? |  
						| 
								|  |  
								| « Последнее редактирование: 29-01-2009 19:21 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #24 : 30-01-2009 13:24 »  |  | 
 
 видим, что код детёв одинаков Что-то типа: template<class T>class Child: public Parent
 {
 public:
 virtual Parent *NEW() { return new T(); }
 virtual void DELETE() { delete dynamic_cast<T *>(this); }
 };
 
 class Child1: public Child<Child1> {};
 class Child2: public Child<Child2> {};
 
 (Не проверял на компилябельность.) |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #25 : 31-01-2009 08:01 »  |  | 
 
 dimka, спасибо, вот наконец то нашлось для меня первое серьёзное применение для шаблонов   только насчёт идентификатора DELETE - в студии он, оказывается, уже зарезервирован, надо другой, но это мелочи. ещё, зачем dynamic_cast<T *>(this) если можно (T*)this ? |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #26 : 31-01-2009 08:28 »  |  | 
 
 Алексей1153++, потому что если dynamic_cast не сможет привести тип, он вернёт null, а delete для null вполне безобиден. В общем случае приведение в C-style опаснее: скажем, если какой-нибудь нехороший человек чем-то не тем специфицирует шаблон. Например, class Child3: public Child<AnotherClass> {};
что тогда будет? Понятно, что в данном контексте такое определение не вполне корректно    Но мало ли чем ещё можно специфицировать шаблон, и приводить всё это к типу, не будучи уверенным, что приведётся... Ошибки во время выполнения будут весьма странные. Я бы, кстати, использовал static_cast - он в этом случае отлично проверяет, чтобы кто чего не натворил, минуя наследование Child: class Parent {};class AnotherClass : public Parent {};
 
 template<class T>
 class Child : public Parent
 {
 public:
 virtual Parent *Create() { return new T(); }
 virtual void Release() { delete static_cast<T *>(this); }
 };
 
 class Child1: public Child<Child1> {};
 class Child2: public Child<Child2> {};
 class Child3: public Child<AnotherClass>{};
 
Child<AnotherClass> компилятор не пропустит, всё остальное - ок. |  
						| 
								|  |  
								| « Последнее редактирование: 31-01-2009 08:47 от Вад » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #27 : 31-01-2009 08:47 »  |  | 
 
 Вад, я думаю, случая, когда dynamic_cast в этом примере вернёт NULL, не будет. Поскольку new T() должен привестись к Parent *. Если T - не потомок Parent, то компилятор на это обидится. Но в целом в данном примере dynamic_cast, конечно, надёжнее static_cast.
 P.S. В С# можно явно указать, что параметр шаблона должен быть потомком какого-то класса. В C++, к сожалению, нельзя.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| Вад | 
								|  | « Ответ #28 : 31-01-2009 09:03 »  |  | 
 
 Вот ещё конструкция, с которой пока не пойму, что делать: class Child4: public Child<Child2> {};Если конструкторы приватные, и в качестве объекта Class4 будет на самом деле существовать объект Class2 - то, вроде, ничего страшного. Но поведение всё равно получается запутанное. А уж если можно явно инстанцировать Class4...  Правильно я понимаю, что из-за срезки нельзя по this установить, какой конкретно тип является спецификацией шаблона? |  
						| 
								|  |  
								| « Последнее редактирование: 31-01-2009 09:08 от Вад » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #29 : 31-01-2009 14:04 »  |  | 
 
 думаю, с кастом тут вы оба преувеличили ) Правило использзование класса я напишу, а кто захочет экспериментировать - флаг ему в шаловливые ручки ) Ну ладно, static_cast оставлю |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	|  |