Как да проверя дали шаблонният параметър на функцията има определен тип?

Да кажем, че имам функция с тип шаблон T и два други класа A и B.

template <typename T>
void func(const T & t)
{
    ...........
    //check if T == A do something
    ...........
    //check if T == B do some other thing
}

Как мога да направя тези две проверки (без да използвам Boost библиотека)?


person Narek    schedule 04.10.2011    source източник


Отговори (3)


Ако буквално просто искате булево значение, за да проверите дали T == A, тогава можете да използвате is_same, налично в C++11 като std::is_same или преди това в TR1 като std::tr1::is_same:

const bool T_is_A = std::is_same<T, A>::value;

Можете тривиално да напишете този малък клас сами:

template <typename, typename> struct is_same { static const bool value = false;};
template <typename T> struct is_same<T,T> { static const bool value = true;};

Често обаче може да откриете, че е по-удобно да опаковате своя разклоняващ се код в отделни класове или функции, които сте специализирали за A и B, тъй като това ще ви даде условие по време на компилиране. За разлика от това, проверката на if (T_is_A) може да се извърши само по време на изпълнение.

person Kerrek SB    schedule 04.10.2011
comment
Какво имаш предвид, направено само по време на изпълнение? is_same<T,A>::value е целочислен постоянен израз. Кодът в if(T_is_A) вероятно ще бъде обект на премахване на мъртъв код в приличен компилатор, което се случва преди време на изпълнение. Проблемът е, че кодът и в двата клона все още трябва да се компилира, преди да бъде елиминиран. - person Steve Jessop; 04.10.2011
comment
@SteveJessop: Е, тази оптимизация е детайл... основната точка е, както казваш, че целият код на клона трябва да бъде валиден код, което е доста ограничение. За разлика от това, не се изисква специализираните шаблони да имат смисъл, освен ако не са действително създадени. - person Kerrek SB; 04.10.2011
comment
Това решение има предимство пред вече предложените, тъй като ако направите нещо и направите нещо друго, дефинирате променлива като двойна и дефинирате променлива като int, техниката за специализация на функцията няма да работи, тъй като тези променливи ще бъдат локални за тези функции. Благодаря за хубавото решение! - person Narek; 05.10.2011

Създайте функционални шаблони със специализации, които ще направят това, което искате.

template <class T>
void doSomething() {}

template <>
void doSomething<A>() { /* actual code */ }

template <class T>
void doSomeOtherThing() {}

template <>
void doSomeOtherThing<B>() { /* actual code */ }

template <typename T>
void func(const T & t)
{
    ...........
    //check if T == A do something
    doSomething<T>();
    ...........
    //check if T == B do some other thing
    doSomeOtherThing<T>();
}
person jpalecek    schedule 04.10.2011
comment
Ако пропуснете изцяло дефиницията на основния шаблон, template <class> void doSomething();, тогава ще получите хубава грешка по време на компилиране, ако типът не е нито A, нито B. - person Kerrek SB; 04.10.2011
comment
@KerrekSB: Всъщност в този случай ще получите грешка във времето за компилиране независимо от T, защото специализацията няма да успее да намери основния си шаблон. Затова са включени и двете :) - person jpalecek; 04.10.2011
comment
Наистина, ще трябва да пропуснете общата дефиниция и да добавите дефиниция за бездействие за doSomething<B> и doSomeOtherThing<A>. - person Steve Jessop; 04.10.2011
comment
Да, погрешно прочетох въпроса на OP като превключване на T, но всъщност това не беше поисканото. Няма значение :-S - person Kerrek SB; 04.10.2011
comment
@SteveJessop: защо? аз не разбирам - person jpalecek; 04.10.2011
comment
@jpalacek: трябва да направиш това, за да получиш ефекта, описан от Kerrek, искам да кажа. Въпреки че като се замисля, тогава може да е безсмислено използването на шаблон изобщо, една претоварена функция за A и B би свършила работа, ако приемем, че кодът, пропуснат от питащия, всъщност използва t. - person Steve Jessop; 04.10.2011
comment
@SteveJessop: Да, но семантиката би била малко по-различна. Ще се нуждае от действителен T като аргумент (не е проблем, OP вероятно иска да го използва така или иначе) и ще се специализира в Ts, които не са A, но могат да се конвертират в T (или T&, зависи как го правите). - person jpalecek; 04.10.2011
comment
Добра точка за преобразуването. Дори ако използвам non-const T& за моето претоварване, тип, получен от A, ще се преобразува, така че е въпрос на това дали питащият действително иска точна проверка на типа (т.е. очаква нарушение на LSP), или е доволен от производни класове на A да се държи като A. Вероятно ако се отдръпнем достатъчно, за да отговорим на този въпрос, ще измислим още повече възможни механизми. - person Steve Jessop; 04.10.2011

Ако искате да имате специална реализация на func за някакъв тип параметър, просто създайте претоварване, специфично за този тип:

template <typename T>
void func(const T & t) {
   // generic code
}

void func(const A & t) {
   // code for A
}
person sth    schedule 04.10.2011