2009-03-16 35 views
50

Tôi đang cố gắng sử dụng typedef từ một phân lớp trong dự án của mình, tôi đã tách biệt sự cố của tôi trong ví dụ bên dưới.sử dụng không hợp lệ loại không đầy đủ

Có ai biết tôi đang đi đâu không?

template<typename Subclass> 
class A { 
    public: 
     //Why doesn't it like this? 
     void action(typename Subclass::mytype var) { 
      (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 

class B : public A<B> { 
    public: 
     typedef int mytype; 

     B() {} 

     void do_action(mytype var) { 
      // Do stuff 
     } 
}; 

int main(int argc, char** argv) { 
    B myInstance; 
    return 0; 
} 

Đây là sản phẩm tôi nhận được:

[email protected]:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp 
test.cpp: In instantiation of ‘A<B>’: 
test.cpp:10: instantiated from here 
test.cpp:5: error: invalid use of incomplete type ‘class B’ 
test.cpp:10: error: forward declaration of ‘class B’ 

Trả lời

57

Lý do là khi instantiating một lớp mẫu, tất cả các tờ khai của mình (không các định nghĩa) của các hàm thành viên của nó cũng được khởi tạo. Mẫu lớp được khởi tạo chính xác khi cần có định nghĩa đầy đủ về chuyên môn. Đó là trường hợp khi nó được sử dụng như một lớp cơ sở ví dụ, như trong trường hợp của bạn.

Vì vậy, những gì xảy ra là A<B> được khởi tạo tại

class B : public A<B> 

tại thời điểm đó B không phải là một loại hoàn chỉnh vẫn chưa (nó là sau cú đúp đóng cửa của định nghĩa lớp). Tuy nhiên, tuyên bố A<B>::action 's đòi hỏi B để được hoàn thành, bởi vì nó là bò trong phạm vi của nó:

Subclass::mytype 

Những gì bạn cần làm là kéo dài thời gian instantiation đến một số điểm mà tại đó B hoàn tất. Một cách để làm điều này là sửa đổi tuyên bố của action để biến nó thành một mẫu thành viên.

template<typename T> 
void action(T var) { 
    (static_cast<Subclass*>(this))->do_action(var); 
} 

Nó vẫn gõ an toàn bởi vì nếu var không phải là của đúng loại, đi qua var-do_action sẽ thất bại.

+1

Tôi giải quyết cho một cơ cấu lại mã của tôi (do một số vấn đề liên quan khác mà tôi không mô tả ở đây) nhưng tôi đã thử nghiệm phương pháp này và nó thực sự khắc phục vấn đề. Cảm ơn! – seanhodges

0

Bạn cần phải sử dụng một con trỏ hoặc tham chiếu như kiểu đúng là không biết đến lúc này trình biên dịch không thể khởi tạo nó.

Thay vì cố gắng:

void action(const typename Subclass::mytype &var) { 
      (static_cast<Subclass*>(this))->do_action(); 
    } 
+0

Tôi đã thử thay đổi nó thành tham chiếu và sau đó là con trỏ và lỗi vẫn giữ nguyên. Tôi hiểu điểm của bạn mặc dù. – seanhodges

2

Bạn lấy được B từ A<B>, do đó, điều đầu tiên trình biên dịch không, một khi nó thấy định nghĩa của lớp B là cố gắng nhanh chóng A<B>. Để thực hiện điều này, cần biết số B::mytype cho thông số action. Nhưng kể từ khi trình biên dịch chỉ là trong quá trình tìm ra định nghĩa thực tế của B, nó không biết loại này được nêu ra và bạn nhận được một lỗi.

Một khoảng cách này là sẽ được khai báo kiểu tham số như một mẫu tham số, thay vì bên trong lớp có nguồn gốc:

template<typename Subclass, typename Param> 
class A { 
    public: 
     void action(Param var) { 
       (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 

class B : public A<B, int> { ... }; 
1

Không chính xác những gì bạn đang hỏi, nhưng bạn có thể làm cho hành động một hàm template thành viên:

template<typename Subclass> 
class A { 
    public: 
     //Why doesn't it like this? 
     template<class V> void action(V var) { 
       (static_cast<Subclass*>(this))->do_action(); 
     } 
}; 

class B : public A<B> { 
    public: 
     typedef int mytype; 

     B() {} 

     void do_action(mytype var) { 
       // Do stuff 
     } 
}; 

int main(int argc, char** argv) { 
    B myInstance; 
    return 0; 
} 
22

Bạn có thể khắc phục điều này bằng cách sử dụng một lớp học đặc điểm:
Nó đòi hỏi bạn thiết lập một lớp học đặc điểm specialsed cho mỗi lớp actuall bạn sử dụng.

template<typename SubClass> 
class SubClass_traits 
{}; 

template<typename Subclass> 
class A { 
    public: 
     void action(typename SubClass_traits<Subclass>::mytype var) 
     { 
       (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 


// Definitions for B 
class B; // Forward declare 

template<> // Define traits for B. So other classes can use it. 
class SubClass_traits<B> 
{ 
    public: 
     typedef int mytype; 
}; 

// Define B 
class B : public A<B> 
{ 
    // Define mytype in terms of the traits type. 
    typedef SubClass_traits<B>::mytype mytype; 
    public: 

     B() {} 

     void do_action(mytype var) { 
       // Do stuff 
     } 
}; 

int main(int argc, char** argv) 
{ 
    B myInstance; 
    return 0; 
} 
Các vấn đề liên quan