2012-01-16 45 views
11

Tôi có lớp cơ sở trông giống như sau.Gọi hàm tạo cơ sở mẫu trong lỗi danh sách khởi tạo thành viên

template<typename T> 
class Base 
{ 
    public: 
     Base(int someValue); 

     virtual T someFunc() =0; 
}; 

template<typename T> 
Base<T>::Base(int someValue) 
{} 

Và sau đó làm như sau.

#include "base.hpp" 

class Foo 
    : public Base<Foo> 
{ 
    public: 
     Foo(int someValue); 

     virtual Foo someFunc(); 
}; 

Foo::Foo(int someValue) 
    : Base(someValue) 
{} 

Tôi nhận được lỗi sau từ gcc 4.2.1.

error: class ‘Foo’ does not have any field named ‘Base’ 

Tôi nên đề cập đến việc biên dịch này tốt trên hộp Fedora của tôi đang chạy gcc 4.6.2. Lỗi này xảy ra khi biên dịch trên máy os x Lion của tôi.

Cảm ơn bạn đã trợ giúp.

EDIT

Có vẻ như tôi không chỉ định loại mẫu trong lớp Foo khi gọi hàm tạo. Sau đây sửa lỗi trong os x.

: Base<Foo>(someValue, parent) 

EDIT

Có điều này trông giống như một lỗi. Những gì tôi đã đề cập trước khi sửa lỗi dưới os x và mã biên dịch tốt trong fedora với sửa chữa đó. Sẽ đi và xem nếu có một bản cập nhật cho gcc trong os x.

+0

[Qt có thể được trừu tượng ra từ này hoàn toàn.] (Http://ideone.com/tSWdI) –

+0

Dup? http://stackoverflow.com/questions/3829040/scope-problems-in-template-c –

Trả lời

8

Đầu tiên:

[C++11: 12.6.2/3]: Một mem-initializer-list có thể khởi tạo một lớp cơ sở sử dụng bất kỳ đẳng cấp hay-decltype đó chứng tỏ rằng loại lớp cơ sở.

[Ví dụ:

struct A { A(); }; 
typedef A global_A; 
struct B { }; 
struct C: public A, public B { C(); }; 
C::C(): global_A() { } // mem-initializer for base A 

-end dụ]

Base phải là một giá trị tiêm-class-name cho các cơ sở ở đây (có nghĩa là, bạn có thể sử dụng nó thay cho Base<T>):

[C++11: 14.6.1/1]:Giống như các lớp bình thường (không phải mẫu), các mẫu lớp học có một tên lớp được tiêm (Điều 9). Bạn có thể sử dụng tên lớp được tiêm làm mẫu mẫu hoặc loại tên. Khi nó được sử dụng với một mẫu đối số-list, như một mẫu đối số cho một mẫu mẫu tham số, hoặc như nhận diện cuối cùng trong xây dựng-type-specifier của một lớp người bạn tuyên bố mẫu, nó đề cập đến chính mẫu lớp đó.Nếu không, nó tương đương với tên mẫu , theo sau là thông số mẫu của mẫu lớp được đính kèm trong <>.

[C++11: 14.6.1/3]: Các tiêm-class-name của một lớp mẫu hay lớp mẫu chuyên môn có thể được sử dụng như một mẫu tên tuổi hoặc một loại tên bất cứ nơi nào nó nằm trong phạm vi. [Ví dụ:

template <class T> struct Base { 
    Base* p; 
}; 

template <class T> struct Derived: public Base<T> { 
    typename Derived::Base* p; // meaning Derived::Base<T> 
}; 

template<class T, template<class> class U = T::template Base> struct Third { }; 
Third<Base<int> > t; // OK: default argument uses injected-class-name as a template 

-end dụ]

tôi đã không tìm thấy bất cứ điều gì để cho biết rằng điều này không áp dụng trong các ctor-initializer, vì vậy tôi muốn nói rằng đây là lỗi trình biên dịch.

Testcase đã được rút gọn của tôi fails in GCC 4.1.2GCC 4.3.4 nhưng succeeds in GCC 4.5.1 (C++11 mode). Nó dường như được giải quyết bởi GCC bug 189; trong the GCC 4.5 release notes:

G ++ hiện đang triển khai DR 176. Trước đây G + + không hỗ trợ bằng cách sử dụng tên lớp được tiêm của một lớp cơ sở mẫu làm tên kiểu và tra cứu tên tìm thấy tuyên bố mẫu trong phạm vi bao gồm của mẫu. Bây giờ tra cứu tên tìm thấy tên lớp được tiêm, có thể được sử dụng làm kiểu hoặc dưới dạng mẫu, tùy thuộc vào có hay không tên được theo sau bởi danh sách đối số mẫu. Là một kết quả của sự thay đổi này, một số mã đã được chấp nhận trước đây có thể vô hình thành vì

  • Các tiêm-class-name là không thể truy cập bởi vì nó là từ một cơ sở tư nhân, hoặc
  • Các injected- không thể sử dụng tên lớp làm đối số cho tham số mẫu mẫu.

Trong cả hai trường hợp này, mã có thể được sửa bằng cách thêm lồng nhau tên-specifier để đặt tên mẫu rõ ràng. Việc đầu tiên có thể được làm việc xung quanh với -fno-access-control; thứ hai chỉ bị từ chối với -pantic.


My lột xuống testcase với Qt trừu tượng ra:

template <typename T> 
struct Base { }; 

struct Derived : Base<Derived> { // I love the smell of CRTP in the morning 
    Derived(); 
}; 

Derived::Derived() : Base() {}; 
+0

Như tôi hiểu anh ta cần thêm một tham số mẫu vào khởi tạo lớp cơ sở của Foos như sau: Foo :: Foo (int someValue, QObject * parent) : Base (someValue, parent) {} – Neox

+1

@Neox: Tại sao?Tại sao cơ sở _injected-class-name_ không đủ? –

+0

Tôi tin rằng đây là [liên kết đến báo cáo lỗi] (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=189) đã được sửa từ gcc 4.5 –

Các vấn đề liên quan