Đây là một OT nhỏ, nhưng tôi nghĩ tôi sẽ để nó ở đây trong trường hợp nó giúp ích cho người khác. Tôi đã tìm kiếm trên Google về chuyên môn hóa mẫu đã dẫn tôi đến đây, và mặc dù câu trả lời của @ maxim1000 là đúng và cuối cùng đã giúp tôi tìm ra các vấn đề của mình, tôi không nghĩ rằng nó quá rõ ràng.
Tình huống của tôi hơi khác một chút (nhưng đủ tương tự để tôi nghĩ câu trả lời này) so với OP. Về cơ bản, tôi đang sử dụng thư viện của bên thứ ba với tất cả các loại lớp khác nhau xác định "loại trạng thái". Trọng tâm của các kiểu này chỉ đơn giản là enum
s, nhưng các lớp đều kế thừa từ một lớp cha chung (trừu tượng) và cung cấp các hàm tiện ích khác nhau, chẳng hạn như nạp chồng toán tử và một static toString(enum type)
hàm. Mỗi trạng thái enum
là khác nhau và không liên quan. Ví dụ, một cái enum
có các trường NORMAL, DEGRADED, INOPERABLE
, một cái khác có AVAILBLE, PENDING, MISSING
, v.v ... Phần mềm của tôi phụ trách quản lý các loại trạng thái khác nhau cho các thành phần khác nhau. Nó đến từ việc tôi muốn sử dụng các toString
chức năng choenum
các lớp, nhưng vì chúng trừu tượng nên tôi không thể khởi tạo chúng trực tiếp. Tôi có thể đã mở rộng từng lớp mà tôi muốn sử dụng, nhưng cuối cùng tôi quyết định tạo một template
lớp, nơi typename
sẽ là bất kỳ trạng thái cụ thể nào enum
mà tôi quan tâm. Có lẽ có thể có một số tranh luận về quyết định đó, nhưng tôi cảm thấy rằng đó là công việc ít hơn nhiều so với việc mở rộng mỗi enum
lớp trừu tượng với một lớp tùy chỉnh của riêng tôi và triển khai các hàm trừu tượng. Và tất nhiên trong mã của tôi, tôi chỉ muốn có thể gọi .toString(enum type)
và để nó in ra biểu diễn chuỗi của điều đó enum
. Vì tất cả những thứ enum
hoàn toàn không liên quan đến nhau, chúng đều cótoString
hàm mà (sau một số nghiên cứu tôi đã học được) phải được gọi bằng cách sử dụng chuyên môn hóa mẫu. Điều đó đã dẫn tôi đến đây. Dưới đây là MCVE về những gì tôi phải làm để làm cho việc này hoạt động chính xác. Và thực sự giải pháp của tôi hơi khác so với @ maxim1000.
Đây là một tệp tiêu đề (được đơn giản hóa rất nhiều) cho enum
s. Trong thực tế, mỗi enum
lớp được định nghĩa trong tệp riêng của nó. Tệp này đại diện cho các tệp tiêu đề được cung cấp cho tôi như một phần của thư viện mà tôi đang sử dụng:
// 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
}
};
thêm dòng này chỉ để tách tệp tiếp theo thành một khối mã khác:
// 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()
{
}
tập tin tiếp theo
// 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_);
}
tập tin tiếp theo
// 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;
}
và kết quả này là:
BEARS1
TIGERS3
Không có manh mối nào nếu đây là giải pháp lý tưởng để giải quyết vấn đề của tôi, nhưng nó đã hiệu quả với tôi. Bây giờ, bất kể tôi sử dụng bao nhiêu kiểu liệt kê, tất cả những gì tôi phải làm là thêm một vài dòng cho toString
phương thức trong tệp .cpp và tôi có thể sử dụng toString
phương thức đã được xác định sẵn trong thư viện mà không cần tự triển khai nó và không cần mở rộng từng enum
lớp tôi muốn sử dụng.