ToString
является членом шаблона другого класса шаблона.
Вы не можете специализировать внутренний шаблон, не специализируя внешний шаблон, first . То есть сначала вы должны специализировать какой-то конкретный экземпляр BasicScalarFormatter
, затем взять его, и только тогда вы можете специализировать конкретный экземпляр его метода-шаблона. Но эта специализация будет распространяться, конечно, только на специализированные BasicScalarFormatter
.
Ваша очевидная цель - не специализировать внешний шаблон, а иметь специализацию для этого члена класса, всех экземпляров внешнего шаблона.
Здесь нет действительно чистых решений, но этот общий шаблон проектирования обычно достаточно прост, чтобы умные компиляторы в конечном итоге оптимизировали дополнительное перенаправление:
#include <string>
template<typename C, typename T> class ToStringHelper {
public:
static std::basic_string<C> helper()
{
return std::basic_string<C>();
}
};
template<typename C> class ToStringHelper<C, bool> {
public:
static std::basic_string<C> helper()
{
return std::basic_string<C>();
}
};
template <class C>
class BasicScalarFormatter
{
public:
typedef std::basic_string<C> String;
template<typename T>
static String ToString(T val)
{
return ToStringHelper<C,T>::helper();
}
};
void foo()
{
BasicScalarFormatter<char> c;
c.ToString(0);
c.ToString(true);
}
Итак, в этот момент вы попадаете в статический метод вспомогательного класса. Ваша конечная цель, очевидно, состоит в том, чтобы использовать что-то, что является частью исходного шаблона. Ну, вы всегда можете передать this
этому helper()
и заставить его что-то с ним сделать или использовать его для вызова метода вызывающего класса.
И затем, как я уже сказал, надеюсь, что ваш компилятор избавится от этого дополнительного уровня косвенности, возможно, с некоторыми inline
ключевыми словами, разбросанными здесь и там, чтобы поощрять его, или использовать грубую силу и использовать расширение вашего компилятора для заставить его все встроить.
Протестировано с gcc 8.