Надо надеяться, Вы понимаете изображения. Мудрый производительностью, они эквивалентны - никакое различие.
РЕДАКТИРОВАНИЕ: ой. Угадайте, что Вы не заботились о той части ответа.
Вы можете только специфицировать его явно, указав все аргументы шаблона. Частичная специализация для функций-членов шаблонов классов не допускается.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
Обходной путь - ввести перегруженные функции, преимущество которых заключается в том, что они все еще находятся в том же классе, и поэтому они имеют одинаковый доступ к переменным-членам, функциям и прочему.
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Обратите внимание, что, переходя к перегруженным функциям и вставляя параметры шаблона в параметр функции, вы можете произвольно «специализировать» свои функции, а также можете шаблонизировать их по мере необходимости. Другой распространенный метод - это отложить до шаблона класса, определенного отдельно
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
. Я считаю, что обычно требуется больше кода, и я считаю, что перегрузку функции легче обрабатывать, в то время как другие предпочитают отложить до шаблона класса. В конце концов, это дело вкуса. В этом случае вы могли бы поместить этот другой шаблон внутрь X
также как вложенный шаблон - в других случаях, когда вы специализируетесь явно, а не только частично, вы не можете этого сделать, потому что вы можете явно указать специализации только в области пространства имен, а не в области класса.
Вы также можете создать такой шаблон SpecializedImpl
только для перегрузки функций (затем он работает аналогично нашему i2t
из предыдущего), как показано в следующем варианте, который оставляет первый переменная параметра тоже (так что вы можете вызывать ее с другими типами, а не только с параметрами шаблона текущего экземпляра)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
Иногда мне кажется, что лучше отложить использование другого шаблона (когда дело касается таких случаев, как массивы и указатели, перегрузка может быть сложной, и тогда для меня было проще просто перенаправить в шаблон класса), а иногда просто перегрузка в шаблоне лучше - особенно если вы действительно пересылаете аргументы функции и если вы касаетесь переменных-членов классов.
Это то, что я придумал, неплохо :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}