Шаблонный метод C , изменяющий поведение на основе класса template

#c #templates

#c #шаблоны

Вопрос:

Я пытаюсь написать шаблонный метод c . Ниже приведен пример кода, демонстрирующий, что я хочу сделать в рамках метода.

 template<class T>
void method(T value) {
    // This string should change based on type T 
    char *str = "Int" or "Float" or .. ;   
    ...
    ...
    std::cout << value << " is of type " << str << std::cout;
}
  

В принципе, поведение (строковое значение в этом примере) метода будет меняться в зависимости от типа T.
Как я мог бы сделать это с помощью template?

Комментарии:

1. Вам действительно нужно, чтобы это был шаблонный метод? Возможно, вы просто сможете использовать некоторые не шаблонные методы перегрузки.

Ответ №1:

Вы можете специализировать свой шаблон на разных типах. Если вы начнете с базового варианта:

 template <class T>
void method(T value);
  

Затем вы можете объявить другое поведение для любого конкретного значения T :

 template <>
void method<int>(int value) {
  // special behavior
}
  

И так далее. Но поскольку меняется только тип ввода вашей функции, вам действительно не нужны шаблоны в этом случае! Вы можете просто перегрузить свою функцию разными типами аргументов:

 void method(int T);
void method(float T);
void method(void* T);
  

РЕДАКТИРОВАТЬ: Использование специализации шаблона для получения имени типа и использования его в другом шаблоне функции:

 template <class T>
std::string type_to_string();

template <>
std::string type_to_string<int>() {
  return "int";
}

template <>
std::string type_to_string<float>() {
  return "float";
}


template <class T>
some_other_function(T value) {
  std::cout << value << " is a " << type_to_string<T>() << std::endl;
}
  

Конечно, вы все еще можете сделать это без шаблонов:

 std::string type_to_string(int) {
  return "int";
}

some_other_function(int value) {
  std::cout << value << " is a " << type_to_string(value) << std::endl;
}
  

Если бы вам пришлось выполнять какие-то сложные вычисления на уровне типа, я бы предложил использовать шаблоны. Но здесь, я думаю, вы можете довольно хорошо выполнить то, что вы хотите, без них. В любом случае, идиоматический способ (с шаблонами или без них) заключается в разделении вашей функции на разные естественные части.

Комментарии:

1. Причина, по которой я хотел использовать шаблон, заключалась в том, что тогда я мог бы поделиться некоторыми частями кода (например, инструкцией печати в конце). Но при перегрузке мне приходится писать целые функции для каждого типа. Я что-то упускаю?

2. Ммм, понятно. Вы могли бы написать функцию, typeToString<T>() специализированную по общим типам, которая возвращала бы строку, соответствующую T . Затем вы могли бы использовать это в своем исходном шаблоне функции.

3. Вычеркните общий код, который, как вы ожидаете, будет повторяться в каждом перегруженном методе, и поместите его в отдельный «служебный» метод. Затем просто вызывайте этот метод ‘utility’ в каждом перегруженном методе.

4. Да. Это, кажется, работает для меня (оба ваших ответа). Спасибо за помощь!

Ответ №2:

У меня в голове сразу несколько способов:

  1. Возможно, у T мог бы быть метод, который возвращает соответствующую строку, и все ваши T предоставляют этот метод.

Тогда вы можете сказать:

char *str = T.gettheapropriatestring();

  1. RTTI и dynamic_cast. Смотрите http://en.wikipedia.org/wiki/Run-time_type_information.

Комментарии:

1. Но… Я действительно думаю, что у Джонатана Стерлинга есть лучший ответ (т. Е. более простое решение), чем у меня.

Ответ №3:

Это зависит от того, насколько сильно и как часто меняется поведение. Если поведение отличается для каждого типа, вы могли бы рассмотреть возможность вообще не использовать шаблон, просто стандартную перегрузку. Если поведение обычно одинаковое, но совершенно разное для одного или двух случаев, вы можете использовать явную специализацию для этих случаев. Если большая часть поведения всегда одинакова, но есть одна небольшая часть, которая меняется, вы можете либо перенести эту часть в перегруженную функцию, либо использовать класс traits:

 template <typename T> CustomBehavior;

template <typename T>
void
function( T value )
{
    //  ...
    CustomBehavior<T>::specialized(...);
    //  ...
}