Este é um pequeno OT, mas pensei em deixar isso aqui para o caso de ajudar alguém. Eu estava pesquisando sobre a especialização de modelos, o que me trouxe até aqui e, embora a resposta de @max1000 esteja correta e, no final das contas, tenha me ajudado a descobrir meus problemas, não achei que fosse muito claro.
Minha situação é um pouco diferente (mas semelhante o suficiente para deixar esta resposta, eu acho) do que os OPs. Basicamente, estou usando uma biblioteca de terceiros com todos os diferentes tipos de classes que definem "tipos de status". O coração desses tipos é simplesmente enum
s, mas todas as classes herdam de um pai comum (abstrato) e fornecem diferentes funções de utilidade, como sobrecarga de operador e uma static toString(enum type)
função. Cada status enum
é diferente um do outro e não está relacionado. Por exemplo, um enum
tem os campos NORMAL, DEGRADED, INOPERABLE
, outro tem AVAILBLE, PENDING, MISSING
, etc. Meu software é responsável por gerenciar diferentes tipos de status para diferentes componentes. Acontece que eu queria utilizar as toString
funções para essesenum
classes, mas como são abstratas, não pude instanciá-las diretamente. Eu poderia ter estendido cada classe que quisesse usar, mas no final decidi criar uma template
classe, onde typename
seria qualquer status concreto que enum
me importasse. Provavelmente algum debate pode ser feito sobre essa decisão, mas eu senti que era muito menos trabalhoso do que estender cada enum
classe abstrata com uma personalizada minha e implementar as funções abstratas. E, claro, no meu código, eu só queria poder chamar .toString(enum type)
e fazer com que ele imprima a representação da string disso enum
. Uma vez que todos os enum
s eram totalmente não relacionados, cada um deles tinha seu própriotoString
funções que (depois de algumas pesquisas que aprendi) tinham que ser chamadas usando a especialização de modelo. Isso me trouxe aqui. Abaixo está um MCVE do que eu tive que fazer para fazer isso funcionar corretamente. E, na verdade, minha solução foi um pouco diferente da de @ maxim1000.
Este é um arquivo de cabeçalho (bastante simplificado) para os enum
s. Na realidade, cada enum
aula foi definida em seu próprio arquivo. Este arquivo representa os arquivos de cabeçalho que são fornecidos a mim como parte da biblioteca que estou usando:
// 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
}
};
adicionar esta linha apenas para separar o próximo arquivo em um bloco de código diferente:
// 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()
{
}
próximo arquivo
// 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_);
}
próximo arquivo
// 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;
}
e isso resulta em:
BEARS1
TIGERS3
Não tenho ideia se essa é a solução ideal para resolver meu problema, mas funcionou para mim. Agora, não importa quantos tipos de enumeração eu acabe usando, tudo que tenho a fazer é adicionar algumas linhas para o toString
método no arquivo .cpp, e posso usar o toString
método já definido das bibliotecas sem implementá-lo sozinho e sem estender cada um enum
classe que eu quero usar.