съвпадение на множество типове за разрешаване на специализация на шаблон

Накратко отхвърлете факта, че нормалното претоварване на функциите ще служи по-добре на този пример. Това е предназначено само като начин да научите за програмирането на шаблони. Като каза това, добре дошли сте да коментирате ползите/разликите, които ще получите от използването на претоварване на функции, в сравнение със специализацията на шаблони на функции (въпреки че това може да заслужава самостоятелен въпрос).


Разгледайте следния пример:

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"), но не съм сигурен дали това изобщо е възможно с C++. Въпреки това, виждал съм неочаквана шаблонна магия да се случва пред очите ми и преди, така че мисля, че е добър въпрос да задам тук.


person lurscher    schedule 02.09.2011    source източник
comment
Ако искате нещо, което съответства на повече от един конкретен тип, тогава това е частична специализация, която не е разрешена за функции.   -  person Kerrek SB    schedule 02.09.2011
comment
здравей @Kerrek, моето разбиране за частична специализация е за специализиране на подмножество от параметрите на шаблона. Имам само един параметър на шаблона тук. Не следя как частичната специализация е уместна тук   -  person lurscher    schedule 02.09.2011
comment
Частичната специализация означава, че резултатът все още е шаблон, а не тип. Помислете например за template <typename> struct X; template <typename T> struct X<T*>; Това е частично.   -  person Kerrek SB    schedule 02.09.2011
comment
@Kerrek, как бихте го направили с помощта на шаблон на функционален обект?   -  person lurscher    schedule 02.09.2011
comment
Увийте нещото в клас и се специализирайте до насита.   -  person Kerrek SB    schedule 02.09.2011
comment
@Kerrek, частта, която не е ясна, е какво трябва да поставя в параметрите на специализацията. За вашия пример за типове указатели ще бъде T*, какво ще бъде в този случай?   -  person lurscher    schedule 02.09.2011


Отговори (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; и също така си припомнете, че плаващите числа се повишават до двойни, когато се предават през променливи аргументи на функцията.

person Kerrek SB    schedule 02.09.2011