Проблем с темплейти в C++

17 отговора 0 прегледа
#1

Проблем с темплейти в 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;
}
=========край========

Изглежда проблемът е във формата на израза в препроцесорните директиви. Някой може ли да подскаже работещо решение?

Финдли
Отговор
в отговор на geri® #2

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);
}


[линк]
Отговор
в отговор на wqw #3

Re: Проблем с темплейти в C++

Благодаря!

Функцията f2() има голяма допълнителна функционалност, за това първия начин не става.

Но вторият начин ще проработи.

Надявам се някой да предложи решение и с препроцесорните директиви.

Финдли
Отговор
в отговор на geri® #4

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");

Отговор
в отговор на Pekoнcтpykтop #5

Re: Проблем с темплейти в C++

Работенето на кода ме подведе да търся в посока препроцесора. Още повече че компилатора създава отделна функция за всеки от типовете които по-нататък се срещат реално с този клас. Има все пак някаква логика щом компилирането става за всеки тип да се очаква че се компилира и съответното условие.

Малко прибързано поисках помощ, и аз почти стигнах до този извод и специално за typeid(). Лошото е че трябва да върви и на други компилатори.

Благодаря, по-горе дадоха добро работно предложение.

Финдли
Отговор
в отговор на geri® #6

Re: Проблем с темплейти в C++

Най-лесно, просто и очевидно става с базов клас.

Отговор
в отговор на geri® #7

И защо препроцесорни директиви?

Ето ти вариант на решение:
#include <typeinfo.h>
template <class T>
void VPtr<T>::f2 (T *a) // аргумента МОЖЕ да се ползва в примера, за какво ти е иначе
{
printf (typeid(*a).name());
printf ("\n");
}

Отговор
в отговор на geri® #8

Финдли

"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
Отговор
в отговор на geri® #9

Re: Проблем с темплейти в C++

Междудругото, защо ти трябва да правиш темплейтна функиция, която да зависи от типа на аргумента, само заради упражнението ли? Понеже ми се струва да е в противоречия със замисъла на темплейтите.

Отговор
в отговор на Om_ #10

Re: Проблем с темплейти в C++

Налага се във връзка с debug-подсистемата в конкретният случай да се разпечата малко информация, зависеща от типовете. И тъй като има ограничение основните класове да не им се пипат дефинициите в момента, а те не са от една и съща йерархия, трябва да се прави подобна кръпка. Иначе темплейтите се ползват в случая много успешно, щото се извършват куп сходни и нестандартни за всичките класове манипулации с адресите им. Предишното решение беше купища еднакви функции повтарящи се за всеки тип.

А препроцесорните дефиниции се наложиха автоматично от следното съображение. Във всяко разклонение се използва един специален debug-макрос, в основата на който е една глобална за цялата функция променлива, която се деструктира автоматично при напускане на функцията. Ако се ползват обикновени if-ове, тази променлива ще се дефинира с видимост само за блока на if-a и полза никаква. Препроцесорните директиви биха решили тоя проблем, стига да работеха. Е, няма пълно щастие, трябваше да се допише debug-системата, както и стана :(

Финдли
Отговор
в отговор на geri® #11

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;
}

Отговор
в отговор на geri® #12

Re: Проблем с темплейти в C++

Специализация?

Отговор
в отговор на vmwr #13

Re: Проблем с темплейти в C++

Какво имаш пред вид?

Финдли
Отговор
в отговор на geri® #14

Re: Проблем с темплейти в C++

template<> class VPtr<K1>
{
....
}

template<> class VPtr<K2>
{
....
}

и т.н.

Може и шаблон на функция да напишеш.

Отговор
в отговор на geri® #15

Re: Проблем с темплейти в C++

Разписания по-горе от wqw "// pyrwi nachin" е пример за специализация на член функция, а "// wtori nachin" за специализация на статични член променливи.

... но те ще работят с MicroSkype-ския Visual C++, иначе би трябвало да има по едно "template<>" в началото на специализациите, както vmwr е показал специализация на клас.

Отговор
в отговор на 1.7miTXE #16

Re: Проблем с темплейти в C++

Благодаря за уточнението.
Засега гоня нещата под MS Visual Studio докато ги стигна :) Най-чисто минаха по "// wtori nachin"

Финдли
Отговор
в отговор на geri® #17

Re: Проблем с темплейти в C++

Втория начин бих го избягвал, щото кода за К1 и К2 го има и в двете инстанциации (за К1 и К2) на темплейта без да е нужно ... т.е. така нареченото раздуване на кода (code bloating).

Отговор
в отговор на 1.7miTXE #18

Re: Проблем с темплейти в C++

В случая общо взето е все едно. Това е код само за debug, така че в случая няма значение. А и така е по-нагледно, защото всичко е събрано на едно място. Има 17 функции като F2, и иначе за всяка от тях трябва да се правят по n допълнителни функции за използуваните класове. Ако трябваше да се променя и основната функционалност в зависимост от типовете, тогава наистина първият начин е по-оптимален.

Финдли
Отговор