Как проверить, имеет ли параметр шаблона функции определенный тип?

Скажем, у меня есть функция с типом шаблона 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
Да, я неправильно понял вопрос ОП как переключатель T, но на самом деле это не то, о чем просили. Ничего себе :-С - person Kerrek SB; 04.10.2011
comment
@SteveJessop: почему? Я не понимаю. - person jpalecek; 04.10.2011
comment
@jpalacek: я имею в виду, что вам нужно сделать это, чтобы получить эффект, описанный Керреком. Хотя, если подумать, тогда может быть вообще бессмысленно использовать шаблон, перегруженная функция для A и B подойдет, предполагая, что код, опущенный спрашивающим, на самом деле использует t. - person Steve Jessop; 04.10.2011
comment
@SteveJessop: Да, но семантика будет немного другой. Ему потребуется фактический T в качестве аргумента (не проблема, OP, вероятно, все равно захочет его использовать), и он будет специализироваться на T, которые не являются A, но могут быть преобразованы в T (или T&, зависит от того, как вы это делаете). - person jpalecek; 04.10.2011
comment
Хорошая мысль о конверсии. Даже если я использую неконстантный 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