2010-01-05 41 views
10

Tôi có một mẫu lớp được lồng trong một mẫu khác. Một phần chuyên nó là dễ dàng: Tôi chỉ cần khai báo một khối template< … > bên trong cha mẹ của nó.chuyên mẫu thành viên mà không có chuyên môn của cha mẹ

Tuy nhiên, tôi cần một chuyên môn từng phần khác xảy ra để chỉ định tất cả các đối số mẫu cục bộ của nó. Điều này làm cho nó thành một chuyên môn rõ ràng. Chuyên môn rõ ràng, vì lý do gì, phải ở phạm vi không gian tên. Để khai báo nó bên ngoài lớp cha của nó, cha mẹ phải được chỉ định, yêu cầu danh sách đối số mẫu không trống. Điều này ngụ ý một phần chuyên môn hóa. Chuyên môn từng phần những gì tôi đang làm và nó được cho là hoạt động ở phạm vi ngoài tùy ý. Nhưng cả GCC và Comeau đều không xác định tham số mẫu trong đề cử cha với các đối số chính thức chuyên môn hóa một phần.

template< class X > struct A { 
    template< class Y > struct B; // initial declaration OK 

    template< class Z > 
    struct B< A<Z> > {}; // partial OK as long as there's a local arg 

    template<> // ERROR: this syntax triggers explicit specialization 
    struct B<int> {}; 
}; 

template<> // ERROR: can't nest template<>s here (why?) 
template< class X > // ERROR: can't deduce X from type of A<X>::B<int> (why?) 
struct A<X>::B<int> {}; 

(tôi rời tất cả các mã không làm việc của tôi ở; nhận xét nó một cách thích hợp để cố gắng có ý nghĩa.)

+0

Nhân tiện, bạn có thể làm việc xung quanh nó bằng cách thêm đối số giả, ví dụ: 'int' luôn là' 0'. Đây là lần đầu tiên tôi chơi với C++ 0x; Tôi đang cố gắng lặp qua một 'tuple'. Tôi đã thực hiện loại điều này trước đây, và nó gây phiền nhiễu rằng C++ 0x 'tuple' là ít mạnh hơn so với Boost ... lặp qua các đối số mẫu là chức năng hữu ích mà không nên là một nghi thức của đoạn văn. Ồ, và cho tất cả những rắc rối của tôi, GCC vẫn là ICE khi tôi sửa tất cả các lỗi. – Potatoswatter

Trả lời

9

Đó là bất hợp pháp theo chuẩn C++ 14.7.3/18:

.... tuyên bố sẽ không chuyên một cách rõ ràng thành viên lớp mẫu nếu các mẫu lớp kèm theo của nó cũng không chuyên biệt rõ ràng là .

+0

Cảm ơn! Tôi biết tôi đã trải qua điều này trước đây, bởi vì nó áp dụng cho tất cả đệ quy mẫu. – Potatoswatter

0

thứ Complex. Mã ban đầu của bạn IC10 của VC10 Beta2, tốt đẹp.

Trước hết, tôi nghĩ bạn có điều này ngược:

template<> 
template< class X > 
struct A<X>::B<int> {}; 

X là một mẫu param để struct A và B là một đầy đủ chuyên môn, vì vậy tôi nghĩ rằng nó phải được điều này:

template< class X > 
template<> 
struct A<X>::B<int> {}; 

Nhưng ngay cả việc này cũng không thể biên dịch được. Văn bản lỗi là thực sự hữu ích, mặc dù:

a.cpp a.cpp (11): lỗi C3212: 'A :: B': một rõ ràng chuyên môn hóa của một mẫu thành viên phải là thành viên của một rõ ràng chuyên môn a.cpp (8): xem tuyên bố của 'A :: B'

Dường như nó chỉ là quy phạm pháp luật chuyên đầy đủ B nếu bạn cũng hoàn toàn chuyên A.

Chỉnh sửa: Ok, tôi đã nghe lại từ một người có thể nói về điều này - để diễn giải, đây là một khu vực rất u ám trong tiêu chuẩn, và đó là một vấn đề mở với Ủy ban C++ để làm sạch nó ("nó" là chuyên môn rõ ràng của thành viên của các mẫu lớp). Trong ngắn hạn, lời khuyên là "Đừng làm điều đó".

+0

Có, tôi nhận thấy tôi đã đăng danh sách đối số lồng nhau "ngược"; Tôi đã thử cả hai cách cho đến khi tôi bị bệnh. Một cách nó không nhìn thấy X và cách khác nó phàn nàn về một phần rõ ràng bên trong. Ngoài ra tùy thuộc vào trình biên dịch được sử dụng, tất nhiên. Tiêu chuẩn này rất mơ hồ và vô tổ chức về công cụ này, nhưng tôi không thấy lý do nào là bất hợp pháp. – Potatoswatter

+0

Tôi hiểu. Tôi không phải là một luật sư ngôn ngữ (mặc dù đôi khi tôi chơi một trong các internets) - nhưng VC10 là rất phù hợp, vì vậy nếu nó nói với tôi một cái gì đó là bất hợp pháp, tôi có xu hướng tin tưởng nó. Hy vọng rằng một người khác có thể nhảy vào với ngôn ngữ-ese mô tả hành vi này. –

0

Atleast công trình này trong VC 2010. Nhưng, tôi không thể viết def. của fun() cho "int" bên ngoài khai báo lớp. EDIT: Thật không may g ++ cũng có vấn đề biên dịch. EDIT: Đoạn code dưới đây làm việc trên VC 2010.

template<typename X> 
class A 
{ 
public: 
    A() 
    { 

    } 

    template<typename Y> 
    struct B 
    { 
     void fun(); 
    }; 

    template<> 
    struct B<int> 
    { 
     void fun() 
     { 
      cout << "Specialized version called\n"; 
     } 
     //void fun(); 
    }; 



public: 

    B<X> b; 
}; 



template<typename X> 
template<typename Y> 
void A<X>::B<Y>::fun() 
{ 
    cout << "templated version called\n"; 
} 

int main() 
{ 
    A<int> a; 
    a.b.fun(); 
    A<float> a1; 
    a1.b.fun(); 
} 
+0

Điều đó rất hữu ích. Tôi muốn nói rằng không có lý do * tốt * các trình biên dịch không nên hỗ trợ tất cả điều này nếu có. Tôi không muốn viết định nghĩa bên ngoài lớp học. Nhưng, tất nhiên, đây là điều đầu tiên tôi thử… – Potatoswatter

4

Tôi có xu hướng không sử dụng các lớp lồng nhau quá nhiều. Khiếu nại chính của tôi là họ có xu hướng làm nổi bật mã của lớp mà họ được lồng vào.

Vì vậy, tôi sẽ đề xuất một cách giải quyết:

namespace detail 
{ 
    template <class X, class Z> class BImpl; 
    template <class X, class Z> class BImpl<X, A<Z> > {}; 
    template <class X> class BImpl<X,int> {}; 
} 

template <class X> 
class A 
{ 
    template <class Z> struct B: BImpl<X,Z> {}; 
}; 

Chỉ cần lưu ý rằng nó đòi hỏi phải vượt qua X như một cuộc tranh cãi để BImpl nếu bao giờ bạn muốn cũng chuyên A. Điều thú vị là trong trường hợp này, tôi kết thúc với chỉ chuyên môn hóa một phần!

+0

Đúng. Sở thích của tôi là dành cho các lớp học cồng kềnh hơn là đại diện bên ngoài cồng kềnh với 'friend's ... tổng số mã là giống nhau, hoặc ít hơn với lồng nhau. Trong trường hợp cụ thể này, lớp cha có một danh sách tham số C++ 0x variadic và nó đang cố truyền một tập hợp con cho con, do đó cũng là variadic. Do đó, không có cách nào chuyển tất cả các đối số của phụ huynh cho đứa trẻ/bạn bè và nêu rõ một số trường hợp cụ thể của đứa trẻ/bạn bè. – Potatoswatter

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