Проблем с темплейти в C++
17 отговора
0 прегледа
Проблем с темплейти в C++
Направо ще сложа примерен тестови работещ файл, в който се вижда проблема, описал съм го в коментарите.
========начало=======
#include <stdio.h>
// Имаме два произволни различни класа
class K1 {};
class K2 {};
// Имаме template-класс, с който искаме по сходен начин да обработваме
// и двата класа
template <class T>
class VPtr
{
public:
T* p; // не се ползва в примера
public:
void f2 (T*);
};
template <class T>
void VPtr<T>::f2 (T *a) // аргумента не се ползва в примера
{
// !!!!! ТУКА Е ПРОБЛЕМА.
// Нужно е да се направи различно действие в зависимост от типа
// на входа на темплейта. Проблемът е в условието на препроцесорните
// директиви по-долу. Нещо много тъпо бъркам.
#if T == K1
printf ("\nclass K1\n"); // Искаме това да се печати ако темплейта
// е с първия клас
#elif T == K2
printf ("\nclass K2\n"); // това да се печати ако темплейта е с втория клас
#endif
// !!!! Проблема е че се печати само първото и в двата случая
}
main ()
{
VPtr<K1> a; // създаваме обект от темплейта с първия клас
a.f2 ((K1*)NULL); // и очакваме да се отпечати първото съобщение
VPtr<K2> b; // създаваме обект от темплейта с втория клас
b.f2 ((K2*)NULL); // и очакваме да се отпечати второто съобщение, обаче грънци
return 0;
}
=========край========
Изглежда проблемът е във формата на израза в препроцесорните директиви. Някой може ли да подскаже работещо решение?
Финдли
========начало=======
#include <stdio.h>
// Имаме два произволни различни класа
class K1 {};
class K2 {};
// Имаме template-класс, с който искаме по сходен начин да обработваме
// и двата класа
template <class T>
class VPtr
{
public:
T* p; // не се ползва в примера
public:
void f2 (T*);
};
template <class T>
void VPtr<T>::f2 (T *a) // аргумента не се ползва в примера
{
// !!!!! ТУКА Е ПРОБЛЕМА.
// Нужно е да се направи различно действие в зависимост от типа
// на входа на темплейта. Проблемът е в условието на препроцесорните
// директиви по-долу. Нещо много тъпо бъркам.
#if T == K1
printf ("\nclass K1\n"); // Искаме това да се печати ако темплейта
// е с първия клас
#elif T == K2
printf ("\nclass K2\n"); // това да се печати ако темплейта е с втория клас
#endif
// !!!! Проблема е че се печати само първото и в двата случая
}
main ()
{
VPtr<K1> a; // създаваме обект от темплейта с първия клас
a.f2 ((K1*)NULL); // и очакваме да се отпечати първото съобщение
VPtr<K2> b; // създаваме обект от темплейта с втория клас
b.f2 ((K2*)NULL); // и очакваме да се отпечати второто съобщение, обаче грънци
return 0;
}
=========край========
Изглежда проблемът е във формата на израза в препроцесорните директиви. Някой може ли да подскаже работещо решение?
Финдли
Re: Проблем с темплейти в C++
#include <stdio.h>
class K1 {};
class K2 {};
template <class T>
class VPtr {
public:
static int type;
T* p;
public:
void f2 (T*) {
if (type == 1) {
printf ("\nclass K1\n");
}
else if (type == 2) {
printf ("\nclass K2\n");
}
}
};
// pyrwi nachin
void VPtr<K1>::f2 (K1 *a) {
printf ("\nexactly K1\n");
}
// wtori nachin
int VPtr<K1>::type = 1;
int VPtr<K2>::type = 2;
void main () {
VPtr<K1> a;
a.f2 ((K1*)NULL);
VPtr<K2> b;
b.f2 ((K2*)NULL);
}
[линк]
Re: Проблем с темплейти в C++
Благодаря!
Функцията f2() има голяма допълнителна функционалност, за това първия начин не става.
Но вторият начин ще проработи.
Надявам се някой да предложи решение и с препроцесорните директиви.
Финдли
Функцията f2() има голяма допълнителна функционалност, за това първия начин не става.
Но вторият начин ще проработи.
Надявам се някой да предложи решение и с препроцесорните директиви.
Финдли
Re: Проблем с темплейти в C++
Удивлявам се как това сравнение изобщо работи.
Както и да е, препроцесора минава кода еднократно преди да се компилира просто замества некви неща с други. Тоест колкото и ифа да сложиш, в крайна сметка в компилирания изпълним код ще отиде само едно нещо.
В C++ няма официален начин да се определи типа на променливата рънтайм. Ако ползваш MS VC++, там имаше някакво typeid(). Тоест директивите трябва да ги заместиш:
if (typeid(T) == typeid(K1)
printf ("\nclass K1\n");
else if (typeid(T) == typeid(K2)
printf ("\nclass K2\n");
В C++ няма официален начин да се определи типа на променливата рънтайм. Ако ползваш MS VC++, там имаше някакво typeid(). Тоест директивите трябва да ги заместиш:
if (typeid(T) == typeid(K1)
printf ("\nclass K1\n");
else if (typeid(T) == typeid(K2)
printf ("\nclass K2\n");
Re: Проблем с темплейти в C++
Работенето на кода ме подведе да търся в посока препроцесора. Още повече че компилатора създава отделна функция за всеки от типовете които по-нататък се срещат реално с този клас. Има все пак някаква логика щом компилирането става за всеки тип да се очаква че се компилира и съответното условие.
Малко прибързано поисках помощ, и аз почти стигнах до този извод и специално за typeid(). Лошото е че трябва да върви и на други компилатори.
Благодаря, по-горе дадоха добро работно предложение.
Финдли
Малко прибързано поисках помощ, и аз почти стигнах до този извод и специално за typeid(). Лошото е че трябва да върви и на други компилатори.
Благодаря, по-горе дадоха добро работно предложение.
Финдли
И защо препроцесорни директиви?
Ето ти вариант на решение:
#include <typeinfo.h>
template <class T>
void VPtr<T>::f2 (T *a) // аргумента МОЖЕ да се ползва в примера, за какво ти е иначе
{
printf (typeid(*a).name());
printf ("\n");
}
#include <typeinfo.h>
template <class T>
void VPtr<T>::f2 (T *a) // аргумента МОЖЕ да се ползва в примера, за какво ти е иначе
{
printf (typeid(*a).name());
printf ("\n");
}
Финдли
"Wha is that at my bower-door?"
"O wha is it but Findlay!"
"Then gae your gate, ye'se nae be here:"
"Indeed maun I," quo' Findlay;
"What mak' ye, sae like a thief?"
"O come and see," quo' Findlay;
"Before the morn ye'll work mischief:"
"Indeed will I," quo' Findlay.
"Gif I rise and let you in"-
"Let me in," quo' Findlay;
"Ye'll keep me waukin wi' your din;"
"Indeed will I," quo' Findlay;
"In my bower if ye should stay"-
"Let me stay," quo' Findlay;
"I fear ye'll bide till break o' day;"
"Indeed will I," quo' Findlay.
"Here this night if ye remain"-
"I'll remain," quo' Findlay;
"I dread ye'll learn the gate again;"
"Indeed will I," quo' Findlay.
"What may pass within this bower"-
"Let it pass," quo' Findlay;
"Ye maun conceal till your last hour:"
"Indeed will I," quo' Findlay.

no_future
"O wha is it but Findlay!"
"Then gae your gate, ye'se nae be here:"
"Indeed maun I," quo' Findlay;
"What mak' ye, sae like a thief?"
"O come and see," quo' Findlay;
"Before the morn ye'll work mischief:"
"Indeed will I," quo' Findlay.
"Gif I rise and let you in"-
"Let me in," quo' Findlay;
"Ye'll keep me waukin wi' your din;"
"Indeed will I," quo' Findlay;
"In my bower if ye should stay"-
"Let me stay," quo' Findlay;
"I fear ye'll bide till break o' day;"
"Indeed will I," quo' Findlay.
"Here this night if ye remain"-
"I'll remain," quo' Findlay;
"I dread ye'll learn the gate again;"
"Indeed will I," quo' Findlay.
"What may pass within this bower"-
"Let it pass," quo' Findlay;
"Ye maun conceal till your last hour:"
"Indeed will I," quo' Findlay.
no_future
Re: Проблем с темплейти в C++
Междудругото, защо ти трябва да правиш темплейтна функиция, която да зависи от типа на аргумента, само заради упражнението ли? Понеже ми се струва да е в противоречия със замисъла на темплейтите.
Re: Проблем с темплейти в C++
Налага се във връзка с debug-подсистемата в конкретният случай да се разпечата малко информация, зависеща от типовете. И тъй като има ограничение основните класове да не им се пипат дефинициите в момента, а те не са от една и съща йерархия, трябва да се прави подобна кръпка. Иначе темплейтите се ползват в случая много успешно, щото се извършват куп сходни и нестандартни за всичките класове манипулации с адресите им. Предишното решение беше купища еднакви функции повтарящи се за всеки тип.
А препроцесорните дефиниции се наложиха автоматично от следното съображение. Във всяко разклонение се използва един специален debug-макрос, в основата на който е една глобална за цялата функция променлива, която се деструктира автоматично при напускане на функцията. Ако се ползват обикновени if-ове, тази променлива ще се дефинира с видимост само за блока на if-a и полза никаква. Препроцесорните директиви биха решили тоя проблем, стига да работеха. Е, няма пълно щастие, трябваше да се допише debug-системата, както и стана :(
Финдли
А препроцесорните дефиниции се наложиха автоматично от следното съображение. Във всяко разклонение се използва един специален debug-макрос, в основата на който е една глобална за цялата функция променлива, която се деструктира автоматично при напускане на функцията. Ако се ползват обикновени if-ове, тази променлива ще се дефинира с видимост само за блока на if-a и полза никаква. Препроцесорните директиви биха решили тоя проблем, стига да работеха. Е, няма пълно щастие, трябваше да се допише debug-системата, както и стана :(
Финдли
Re: Проблем с темплейти в C++
Нещо такова няма ли да ти свърши работа?
#include "stdafx.h"
#include <stdio.h>
#define MY_DEBUG
class K1 {};
class K2 {};
class K1Debug:public K1
{
public:
static void PrintInfo(){printf ("\nclass K1\n");}
};
class K2Debug:public K2
{
public:
static void PrintInfo() {printf ("\nclass K2\n");}
};
#ifdef MY_DEBUG
#define K1 K1Debug
#define K2 K2Debug
#endif
template <class T>
class VPtr
{
public:
T* p;
public:
void f2 (T*);
};
template <class T>
void VPtr<T>::f2 (T *a) // аргумента не се ползва в примера
{
#ifdef MY_DEBUG
T::PrintInfo();
#endif
}
int _tmain(int argc, _TCHAR* argv[])
{
VPtr<K1> a;
a.f2 ((K1*)NULL);
VPtr<K2> b;
b.f2 ((K2*)NULL);
return 0;
}
#include "stdafx.h"
#include <stdio.h>
#define MY_DEBUG
class K1 {};
class K2 {};
class K1Debug:public K1
{
public:
static void PrintInfo(){printf ("\nclass K1\n");}
};
class K2Debug:public K2
{
public:
static void PrintInfo() {printf ("\nclass K2\n");}
};
#ifdef MY_DEBUG
#define K1 K1Debug
#define K2 K2Debug
#endif
template <class T>
class VPtr
{
public:
T* p;
public:
void f2 (T*);
};
template <class T>
void VPtr<T>::f2 (T *a) // аргумента не се ползва в примера
{
#ifdef MY_DEBUG
T::PrintInfo();
#endif
}
int _tmain(int argc, _TCHAR* argv[])
{
VPtr<K1> a;
a.f2 ((K1*)NULL);
VPtr<K2> b;
b.f2 ((K2*)NULL);
return 0;
}
Re: Проблем с темплейти в C++
template<> class VPtr<K1>
{
....
}
template<> class VPtr<K2>
{
....
}
и т.н.
Може и шаблон на функция да напишеш.
{
....
}
template<> class VPtr<K2>
{
....
}
и т.н.
Може и шаблон на функция да напишеш.
Re: Проблем с темплейти в C++
Разписания по-горе от wqw "// pyrwi nachin" е пример за специализация на член функция, а "// wtori nachin" за специализация на статични член променливи.
... но те ще работят с MicroSkype-ския Visual C++, иначе би трябвало да има по едно "template<>" в началото на специализациите, както vmwr е показал специализация на клас.
... но те ще работят с MicroSkype-ския Visual C++, иначе би трябвало да има по едно "template<>" в началото на специализациите, както vmwr е показал специализация на клас.
Re: Проблем с темплейти в C++
Благодаря за уточнението.
Засега гоня нещата под MS Visual Studio докато ги стигна :) Най-чисто минаха по "// wtori nachin"
Финдли
Засега гоня нещата под MS Visual Studio докато ги стигна :) Най-чисто минаха по "// wtori nachin"
Финдли
Re: Проблем с темплейти в C++
Втория начин бих го избягвал, щото кода за К1 и К2 го има и в двете инстанциации (за К1 и К2) на темплейта без да е нужно ... т.е. така нареченото раздуване на кода (code bloating).
Re: Проблем с темплейти в C++
В случая общо взето е все едно. Това е код само за debug, така че в случая няма значение. А и така е по-нагледно, защото всичко е събрано на едно място. Има 17 функции като F2, и иначе за всяка от тях трябва да се правят по n допълнителни функции за използуваните класове. Ако трябваше да се променя и основната функционалност в зависимост от типовете, тогава наистина първият начин е по-оптимален.
Финдли
Финдли