To trochę OT, ale pomyślałem, że zostawię to tutaj na wypadek, gdyby pomogło to komuś innemu. Szukałem w Google o specjalizacji szablonów, która doprowadziła mnie do tego, i chociaż odpowiedź @ maxim1000 jest prawidłowa i ostatecznie pomogła mi rozwiązać moje problemy, nie sądziłem, że jest to zbyt jasne.
Moja sytuacja jest trochę inna (ale na tyle podobna, żeby zostawić tę odpowiedź, jak myślę) niż PO. Zasadniczo używam biblioteki innej firmy z różnymi rodzajami klas, które definiują „typy statusu”. Sercem tych typów jest po prostu enum
s, ale wszystkie klasy dziedziczą po wspólnym (abstrakcyjnym) rodzicu i zapewniają różne funkcje użytkowe, takie jak przeciążanie operatora i static toString(enum type)
funkcja. Każdy status enum
różni się od siebie i nie ma ze sobą związku. Na przykład, jeden enum
ma pola NORMAL, DEGRADED, INOPERABLE
, inny ma AVAILBLE, PENDING, MISSING
itd. Moje oprogramowanie zarządza różnymi rodzajami statusów różnych komponentów. Doszło do tego, że chciałem do tego wykorzystać te toString
funkcjeenum
klasy, ale ponieważ są abstrakcyjne, nie mogłem ich bezpośrednio utworzyć. Mógłbym przedłużyć każdą klasę, z której chciałem korzystać, ale ostatecznie zdecydowałem się stworzyć template
klasę, w której typename
byłby taki konkretny status, na którym enum
mi zależy. Prawdopodobnie można dyskutować na temat tej decyzji, ale czułem, że było to o wiele mniej pracy niż rozszerzenie każdej enum
klasy abstrakcyjnej o własną, niestandardową i implementowanie funkcji abstrakcyjnych. I oczywiście w moim kodzie chciałem mieć możliwość wywołania .toString(enum type)
i wydrukowania reprezentacji ciągu enum
. Ponieważ wszystkie enum
były zupełnie niepowiązane, każdy z nich miał swoje własnetoString
funkcje, które (po pewnych badaniach, których się dowiedziałem) musiały być wywoływane przy użyciu specjalizacji szablonowej. To doprowadziło mnie tutaj. Poniżej znajduje się MCVE tego, co musiałem zrobić, aby to działało poprawnie. I faktycznie moje rozwiązanie było trochę inne niż @ maxim1000.
To jest (znacznie uproszczony) plik nagłówkowy dla enum
s. W rzeczywistości każda enum
klasa została zdefiniowana w swoim własnym pliku. Ten plik reprezentuje pliki nagłówkowe, które są dostarczane do mnie w ramach biblioteki, której używam:
#include <string>
class Enum1
{
public:
enum EnumerationItem
{
BEARS1,
BEARS2,
BEARS3
};
static std::string toString(EnumerationItem e)
{
}
};
class Enum2
{
public:
enum EnumerationItem
{
TIGERS1,
TIGERS2,
TIGERS3
};
static std::string toString(EnumerationItem e)
{
}
};
dodanie tej linii tylko po to, aby oddzielić następny plik do innego bloku kodu:
#include <string>
template <typename T>
class TemplateExample
{
public:
TemplateExample(T t);
virtual ~TemplateExample();
std::string toString();
private:
T type_;
};
template <typename T>
TemplateExample<T>::TemplateExample(T t)
: type_(t)
{
}
template <typename T>
TemplateExample<T>::~TemplateExample()
{
}
następny plik
#include <string>
#include "enums.h"
#include "TemplateExample.h"
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
return Enum1::toString(type_);
}
template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
return Enum2::toString(type_);
}
następny plik
#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;
}
i to daje:
BEARS1
TIGERS3
Nie mam pojęcia, czy jest to idealne rozwiązanie mojego problemu, ale zadziałało. Teraz, bez względu na to, ile typów wyliczeń ostatecznie używam, wszystko, co muszę zrobić, to dodać kilka wierszy dla toString
metody w pliku .cpp i mogę użyć metody już zdefiniowanej w bibliotekach toString
bez jej samodzielnego wdrażania i bez rozszerzania każdej z nich enum
klasa, której chcę użyć.