7

có thể bằng cách nào đó làm cho một đặc điểm kỹ thuật mẫu một phần một lớp bạn bè không? I E. xem xét bạn có mẫu sau lớpMẫu C++: Thông số kỹ thuật một phần của mẫu và Lớp bạn bè

template <class T> class X{ 
    T t; 
}; 

Bây giờ bạn có chuyên ngành một phần, ví dụ, đối với con trỏ

template <class T> class X<T*>{ 
    T* t; 
}; 

Những gì tôi muốn đạt được là tất cả có thể X<T*> là một lớp người bạn của X<S> cho BẤT CỨ S. I E. X<A*> phải là bạn của X<B>.

Tất nhiên, tôi nghĩ về một tuyên bố người bạn mẫu bình thường trong X:

template <class T> class X{ 
    template <class S> friend class X<S*>; 
} 

Tuy nhiên, điều này không biên dịch, g ++ nói với tôi điều này:

test4.cpp: 34: 15: lỗi : chuyên môn hóa của 'template<class T> class X' phải xuất hiện ở phạm vi không gian tên

test4.cpp: 34: 21: lỗi: một phần chuyên môn hóa 'X<S*>' tuyên bố 'người bạn'

Điều này không thể thực hiện được hay có cách nào khác không?

Lý do tại sao tôi yêu cầu là tôi cần một constructor trong X<T*> tạo ra lớp này từ một tùy X<S> (S phải là một subtype của T).

Mã này trông như thế này:

template <class T> class X<T*>{ 
    T* t; 

    template<class S> 
    X(X<S> x) : t(&(x.t)) {} //Error, x.t is private 
} 

Bây giờ, trình biên dịch phàn nàn, tất nhiên, đó không phải là x.t visibile trong constructor vì nó là tư nhân. Đây là lý do tại sao tôi cần một lớp người bạn chuyên môn hóa một phần.

+1

Chức năng 'get' có thực sự nằm ngoài câu hỏi không? Điều này có vẻ sạch hơn rất nhiều với tôi và tránh tất cả các bạn bè mẫu điên rồ. – pmr

+0

nó sẽ làm việc trong ví dụ này có thể. Tuy nhiên, có thể có dữ liệu không được tiết lộ cho công chúng mà chỉ cho các chuyên môn về mẫu. Câu hỏi đặt ra là nếu hành vi này là có thể bằng cách nào đó. – gexicide

Trả lời

3

Trong C++, bạn có thể cấp quyền truy cập vượt quá private trên bốn cấp độ.

  • hoàn toàn public truy cập (xem câu trả lời PMR của)
  • truy cập trong hệ thống phân cấp thừa kế (protected, không thích hợp ở đây)
  • một mẫu cơ sở friend (xem câu trả lời này)
  • để một tổ chức phi mẫu hoặc đầy đủ chuyên ngành friend (quá yếu để giải quyết trường hợp sử dụng của bạn)

Không có đặt cược cách giữa ween hai loại tình bạn sau này.

Từ §14.5.4 tiêu chuẩn C++ :.

Friend declarations shall not declare partial specializations.

Tuyên bố sau sẽ cho phép bạn thực hiện những gì bạn cần. Nó cung cấp cho bạn một bàn tay miễn phí để truy cập bất kỳ chuyên môn nào về mẫu của bạn từ bất kỳ chuyên môn nào khác, nhưng vẫn chỉ trong phạm vi X. Nó dễ chấp nhận hơn những gì bạn yêu cầu.

template<class T> class X 
{ 
    template<class Any> friend class X; 
    public: 
     ... 
}; 
1

Chúng ta có thể định nghĩa một getter bảo vệ bởi một phím định nghĩa trong X.

#include <type_traits> 

template <class T> class X{ 
    T t; 
public: 
    struct Key { 
    template<typename S> 
    Key(const X<S>&) { 
     static_assert(std::is_pointer<S>::value, "Not a pointer"); 
    } 
    }; 

    const T& get(Key) const { return t; } 
    T& get(Key) { return t; } 
}; 

template <class T> class X<T*> { 
    T* t; 
public: 
    template<class S> 
    X(X<S>& x) : t(&(x.get(typename X<S>::Key(*this)))) {} 
}; 

int main() 
{ 
    X<int> x1; 
    X<int*> x2(x1); 
    return 0; 
} 

này vẫn có một số điểm yếu. Mọi người có một số X<T*> hiện có thể sử dụng get. Nhưng bây giờ điều này đã trở nên khó hiểu đến nỗi không ai có thể xem xét số . Tôi muốn chọn một công thức đơn giản.

+1

Về cơ bản, tất cả mọi người với một 'nullptr' có thể sử dụng' get'. Có vẻ như chúng tôi có một cuộc thi ở đây. –

+0

@JirkaHanika Bạn có thể cố gắng giải quyết vấn đề đó bằng một quá tải 'null_ptr', nhưng nó sẽ không làm cho nó tốt hơn. – pmr

+1

Có, tất cả mọi người có chữ '0' vẫn có thể sử dụng' get'. –

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