Это маленький ОТ, но я решил оставить это здесь на случай, если это поможет кому-то еще. Я гуглил о специализации шаблонов, которая привела меня сюда, и хотя ответ @ maxim1000 был правильным и в конечном итоге помог мне разобраться в моих проблемах, я не думал, что это было совершенно ясно.
Моя ситуация немного отличается (но я думаю, что она достаточно похожа, чтобы оставить этот ответ), чем у ОП. По сути, я использую стороннюю библиотеку со всеми видами классов, которые определяют «типы статуса». Сердцем этих типов являются просто enum
s, но все классы наследуются от общего (абстрактного) родителя и предоставляют различные вспомогательные функции, такие как перегрузка операторов и функция static toString(enum type)
. Каждый статус enum
отличается друг от друга и не связан. Например, у одного enum
есть поля NORMAL, DEGRADED, INOPERABLE
, у другого - AVAILBLE, PENDING, MISSING
и т. Д. Мое программное обеспечение отвечает за управление различными типами статусов для разных компонентов. Это произошло из-за того, что я хотел использовать функции toString
для этих классов enum
, но, поскольку они абстрактные, я не смог создать их экземпляр напрямую. Я мог бы расширить каждый класс, который хотел использовать, но в конечном итоге я решил создать класс template
, где typename
будет любым конкретным статусом enum
, который меня волнует. Вероятно, могут возникнуть некоторые споры по поводу этого решения, но я чувствовал, что это была намного меньшая работа, чем расширение каждого абстрактного enum
класса с помощью моего собственного и реализация абстрактных функций. И, конечно, в моем коде я просто хотел иметь возможность вызывать .toString(enum type)
и заставить его печатать строковое представление этого enum
. Так как все enum
были совершенно не связаны, у каждого из них были свои toString
функции, которые (после некоторых исследований, которые я изучил) пришлось вызывать с использованием специализации шаблона. Это привело меня сюда. Ниже MCVE того, что я должен был сделать, чтобы сделать эту работу правильно. И на самом деле мое решение немного отличалось от @ maxim1000.
Это (очень упрощенный) заголовочный файл для enum
s. В действительности каждый класс enum
был определен в своем собственном файле. Этот файл представляет заголовочные файлы, которые предоставляются мне как часть библиотеки, которую я использую:
// file enums.h
#include <string>
class Enum1
{
public:
enum EnumerationItem
{
BEARS1,
BEARS2,
BEARS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
class Enum2
{
public:
enum EnumerationItem
{
TIGERS1,
TIGERS2,
TIGERS3
};
static std::string toString(EnumerationItem e)
{
// code for converting e to its string representation,
// omitted for brevity
}
};
добавление этой строки только для разделения следующего файла на другой блок кода:
// file TemplateExample.h
#include <string>
template <typename T>
class TemplateExample
{
public:
TemplateExample(T t);
virtual ~TemplateExample();
// this is the function I was most concerned about. Unlike @maxim1000's
// answer where (s)he declared it outside the class with full template
// parameters, I was able to keep mine declared in the class just like
// this
std::string toString();
private:
T type_;
};
template <typename T>
TemplateExample<T>::TemplateExample(T t)
: type_(t)
{
}
template <typename T>
TemplateExample<T>::~TemplateExample()
{
}
следующий файл
// file TemplateExample.cpp
#include <string>
#include "enums.h"
#include "TemplateExample.h"
// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
return Enum1::toString(type_);
}
template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
return Enum2::toString(type_);
}
следующий файл
// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"
int main()
{
TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);
std::cout << t1.toString() << std::endl;
std::cout << t2.toString() << std::endl;
return 0;
}
и это выводит:
BEARS1
TIGERS3
Понятия не имею, является ли это идеальным решением для решения моей проблемы, но оно сработало для меня. Теперь, независимо от того, сколько типов перечисления я в конечном итоге использую, все, что мне нужно сделать, это добавить несколько строк для метода toString
в файл .cpp, и я могу использовать уже определенный библиотеками метод toString
без реализации это сам и без расширения каждого enum
класса, который я хочу использовать.