Сопоставление нескольких типов для разрешения специализации шаблона

Кратко отвергните тот факт, что нормальная перегрузка функций будет служить этому примеру лучше. Это подразумевается только как способ узнать о программировании шаблонов. Сказав это, вы можете прокомментировать преимущества/различия, которые вы получите от использования перегрузки функций, по сравнению с специализированной функцией шаблона (хотя это может заслуживать самого себя).


Рассмотрим следующий пример:

template <typename T>
inline void ToString(T value, char* target, size_t max_size );

template <>
inline void ToString<float>(float value, char* target, size_t max_size)
{
   snprintf( target , max_size , "%f" , value);
}

template <>
inline void ToString<double>(double value, char* target, size_t max_size)
{
    snprintf( target , max_size , "%f" , value);
}

Есть ли способ написать только одну из этих специализаций, которые соответствуют типам float и double?

В принципе, я предвижу писать специализацию шаблона для типа шаблона, которая будет соответствовать как float, так и double (как тип совпадения типа "float или double" ), но я не уверен, что это вообще возможно С++. Тем не менее, я видел, что перед моими глазами случается неожиданная магия шаблона, поэтому я думаю, что здесь есть хороший вопрос.

Ответ 1

Здесь стандартная идиома решения:

#include <type_traits>
#include <cstdio>


// Helper class

template <typename T>
struct Printer
{
  static typename std::enable_if<std::is_floating_point<T>::value, int>::type
  print(T x, char * out, std::size_t n)
  {
    return std::snprintf(out, n, "%f", x);
  }
};

// Convenience function wrapper

template <typename T> int print(T x, char * out, std::size_t n)
{
  return Printer<T>::print(x, out, n);
}

void f()
{
  char a[10];

  Printer<double>::print(1.2, a, 10);  // use helper class
  print(1.4f, a, 10);                  // wrapper deduces type for you
}

Вы получите ошибку времени компиляции, если вы вызываете либо конструкцию с неплавающим типом. Остерегайтесь, хотя это может ошибочно работать для длинных удвоений, для которых требуется спецификатор формата %Lf; и также помните, что float получает повышение до удвоения при передаче через аргументы вариационной функции.