Tôi đang sử dụng lớp của mình làm tham số mẫu của một lớp cha và lớp cha sử dụng nó trong đối số mẫu (mặc dù sizeof()).Sử dụng lớp con làm tham số mẫu của một lớp cơ sở và như một tham số tên lồng nhau
Và trình biên dịch mang lại cho tôi:
lỗi: loại không đầy đủ 'Invoker :: workerClass {aka MyClass}' được sử dụng trong tên lồng nhau specifier
Tuy nhiên, lớp được được xác định rõ trong file . Tôi đoán điều này là bởi vì lớp trẻ không được khởi tạo tại thời điểm khởi tạo của lớp cơ sở, nhưng điều đó xảy ra với CRTP và không có vấn đề gì.
Lý do tôi sử dụng lớp con trong đối số mẫu là thực hiện cuộc gọi hàm khác nếu lớp con có hoặc không có hàm cụ thể.
Dưới đây là một mã tối thiểu để thử nghiệm
/* Structure similar to boost's enable if, to use
SFINAE */
template <int X=0, class U = void>
struct test {
typedef U type;
};
enum Commands {
Swim,
Fly
};
/* Structure used for template overloading,
as no partial function template specialization available */
template<Commands T>
struct Param {
};
template <class T>
class Invoker
{
public:
typedef T workerClass;
workerClass *wc() {
return static_cast<workerClass*>(this);
}
template <Commands command>
void invoke() {
invoke2(Param<command>());
}
/* If the child class has those functions, call them */
/* Needs template paramter Y to apply SFINAE */
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
invoke2(Param<Fly>) {
wc()->fly();
}
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::swim))>::type
invoke2(Param<Swim>) {
wc()->shoot();
}
template<Commands command>
void invoke2(Param<command>) {
/* Default action */
printf("Default handler for command %d\n", command);
}
};
template <class T, class Inv = Invoker<T> >
class BaseClass : public Inv
{
public:
template<Commands command>
void invoke() {
Inv::template invoke<command>();
}
};
class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}
/* void fly(); */
};
void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}
Các lỗi xảy ra tại dòng:
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
Vì vậy, là có bất kỳ trình biên dịch hỗ trợ này, hoặc là này explicitely xác định bởi các tiêu chuẩn như sử dụng mẫu không hợp lệ? Tôi có phải thay đổi cách tôi đang làm điều này và tìm một cách xung quanh? CRTP đang cho tôi hy vọng mã có thể hợp lệ, nhưng tôi không chắc chắn.
Nếu điều này thực sự là không thể, thì tại sao chính xác và tại sao CRTP hoạt động?
Vâng, vấn đề là rõ ràng ít nhất là: Bạn đang làm cho một định nghĩa đệ quy tự tham chiếu: 'BaseClass 'đòi hỏi sự hoàn hảo' MyClass' vì của' decltype 'expression, nhưng' MyClass' yêu cầu một 'BaseClass ' đầy đủ như là một lớp cơ sở. –
Bạn cần phải ẩn các chuyên môn đằng sau một lớp bổ sung của indirection để chúng không được đánh giá như là một phần của định nghĩa lớp cơ sở. Đặt chúng trong một loại lồng nhau tư nhân và tất cả sẽ làm việc tốt. – ildjarn
CRTP là khó khăn vì lý do chính xác này, vấn đề bạn đang phải đối mặt là dễ hiểu: mẫu cơ sở được khởi tạo như một phần của khai báo lớp, tại thời điểm chưa hoàn thành (nghĩ rằng kiểu vẫn phụ thuộc vào cái gì mẫu cơ sở có thể thêm vào, do đó không có cách nào trình biên dịch có thể biết được kiểu dẫn xuất sẽ giống như thế nào nếu không xử lý mẫu cơ bản trước tiên - cơ sở đó có thể thêm các thuộc tính thành viên thay đổi kích thước hoặc các hàm thành viên ảo có thể thay đổi ý nghĩa của các khai báo hàm trong kiểu dẫn xuất) –