2011-02-03 20 views
7

Không thể kết bạn với thông số mẫu vì tiêu chuẩn không cho phép nó. Làm thế nào tôi có thể có được hiệu quả điều tương tự sau đó?Kết bạn với thông số mẫu

Điều tôi muốn về cơ bản là một loại không thể sử dụng được bên ngoài đối tượng sở hữu nó. Tại sao thay vì quan điểm nhưng nếu bạn thực sự phải biết, tôi đang cố gắng xây dựng một bộ con trỏ thông minh trả lời vấn đề chia sẻ tài nguyên sở hữu. Vì vậy những gì tôi đang tìm cách để làm một cái gì đó giống như vậy, nếu nó làm việc:

template < typename T, typename Owner > 
struct accessible_member 
{ 
private: 
    accessible_member() : val(T()) {} 
    accessible_member(T const& t) : val(t) {} 

    operator T&() { return val; } 
    operator T const&() const { return val; } 

    member_ptr<T> operator &() { return member_ptr<T>(val); } 

    friend class Owner; 
}; 

Vì vậy, một lớp không thể giữ đối tượng này như một thành viên trừ khi nó tuyên bố bản thân chủ sở hữu, và nếu nó đủ ngớ ngẩn để lộ nó như là, nó sẽ không thể sử dụng bên ngoài lớp học là ngu ngốc.

+2

Tôi không thấy điểm cố gắng ngăn chặn mã braindead (như trong đoạn cuối). Trong C++, bạn chỉ cần chấp nhận rằng ai đó có thể phá vỡ mã của bạn nếu họ cố gắng hết sức. –

+1

@Fred - đối số ngớ ngẩn đó có thể được sử dụng để chống lại bất kỳ và tất cả các nỗ lực để đưa ra các biện pháp an toàn mã, bao gồm 'const' và RAII. Bạn có thể làm việc theo một triết lý khác nhưng tôi viết theo hướng dẫn rằng cấu trúc của bạn nên dễ sử dụng đúng và khó sử dụng không chính xác. Toàn bộ vấn đề trong chính cấu trúc là giới thiệu các biện pháp an toàn không được cung cấp bởi bất kỳ thứ gì khác. Tôi thấy sự phản đối của bạn đối với câu hỏi của tôi dư thừa, không đúng chỗ và khá thẳng thắn. –

+2

@NoahRoberts: 1) Điều này có vẻ không dễ sử dụng. 2) Const và RAII dễ sử dụng không chính xác. 3) Làm thế nào bạn có thể tìm thấy * của tôi * thiếu hiểu biết ("Tôi không thấy điểm") để được tấn công? Bạn có bị xúc phạm thay mặt tôi để bảo vệ bản thân tôi khỏi tôi không? –

Trả lời

3

Bạn có thể sử dụng điều này, và sau đó cho phép tất cả các chủ sở hữu kế thừa từ Chủ sở hữu.

Sau đó, bạn có thể sử dụng lớp Chủ sở hữu để quấn riêng các phương pháp được sử dụng trong accessible_member.
có thể truy cập_member hiện có thể truy cập Chủ sở hữu. Bạn bè không được kế thừa, vì vậy bạn có thể cung cấp (bọc) các phương thức cần thiết để tất cả các lớp kế thừa Chủ sở hữu có thể sử dụng accessible_member.

Đó là giải pháp cấp 2 nhưng nó giữ mức đóng gói.

template < typename U > 
struct Owner 
{ 
    protected: 
    accessible_member<U> newAccessible_member() { return accessible_member<U>(); } 
    accessible_member<U> newAccessible_member(U const& u) { return accessible_member<U>(u); } 
    ..... 

}; 

template < typename T > 
struct accessible_member 
{ 
private: 
    accessible_member() : val(T()) {} 
    accessible_member(T const& t) : val(t) {} 

    operator T&() { return val; } 
    operator T const&() const { return val; } 

    member_ptr<T> operator &() { return member_ptr<T>(val); } 


    template < typename U> friend class Owner; 
}; 

Sau đó, bạn có thể sử dụng accessible_member gián tiếp trong cấu trúc mà kế thừa từ Chủ đầu tư sử dụng các phương pháp bảo vệ:

struct Blah: Owner<int> 
{ 
    void Dosomething() { 
     accessible_member<int> blah= newAccessible_member(); 
    } 
}; 

Nhìn vào ví dụ cuối cùng tại Template Friends.

+1

Tình bạn không được thừa hưởng, vì vậy tôi không thấy cách thức này sẽ hoạt động. –

+0

Ông có thể sử dụng chủ sở hữu như một wrapper và bọc các phương pháp tư nhân trong chủ sở hữu. –

+0

Tôi không hiểu mục tiêu của câu trả lời này, cũng không phải là nhận xét. –

0

Điều gì đơn giản là xác định loại lồng nhau riêng lẻ được kế thừa đáng kể từ access_member? Một cái gì đó giống như

class Owner 
{ 
    template < typename T > 
    class accessible_member : public ::accessible_member<T> {}; 
}; 

Tất nhiên điều đó vẫn có nghĩa là loại accessible_member gốc có sẵn cho bất kỳ ai để nó có thể không được sử dụng nhiều để nghĩ về nó.

+0

Nhưng nếu bạn đã làm Chủ sở hữu một người bạn của Chủ sở hữu :: accessible_member và được kế thừa riêng tư :: accessible_member, điều này có thể hoạt động. Nó sẽ yêu cầu rất nhiều bản chuyển tiếp boilerplate trong Owner :: accessible_member, mặc dù. –

5

Bạn đúng về C++ 98/03. Tuy nhiên C++ 0x (n3225 11.4/3) cho phép bạn làm điều này với cú pháp này:

friend Owner; 

Xem trình biên dịch của bạn có cho phép bạn làm điều đó không. Thử bật hỗ trợ C++ 0x. Nếu không thì cách giải quyết là xấu xí:

struct Owner 
{ 
    typedef Owner self; 
}; 

...

Sau đó, tùy thuộc vào trình biên dịch của bạn một trong số:

friend typename Owner::self; 

hay:

friend class Owner::self; 
+1

Có gì sai với chỉ 'typedef Owner Owner_typedef; lớp bạn bè Owner_typedef; '?Trong mọi trường hợp, việc chọn cùng tên cho cấu trúc như tham số mẫu là một ý tưởng thực sự tồi. –

+0

Bạn có thể thả yêu cầu loại lồng nhau 'tự' vào tham số mẫu bằng cách sử dụng 'mẫu cấu trúc bản sắc {typedef T type; }; 'và thay đổi chủ sở hữu :: tự để idenity :: loại, và có nó làm việc trên cùng một trình biên dịch? –

+0

@BenVoigt: Tại sao lại là một ý tưởng tồi? Nó chỉ được sử dụng như một ví dụ ở đây, trong mọi trường hợp. –

1

7.1.5.3 p2 nói:

[Lưu ý: đây ngụ ý rằng, trong một mẫu lớp với một mẫu kiểu tham số T, việc kê khai lớp friend T; bị mờ.]

Kết quả là, bất kỳ giải pháp nào cho phép bạn thực hiện theo bất kỳ nghĩa nào sẽ không tuân thủ tiêu chuẩn.

+2

Trích dẫn tiêu chuẩn giải quyết tình huống không chính xác là câu trả lời, nhưng chắc chắn nó không xứng đáng được giảm giá. –

+2

Không giải quyết câu hỏi thực sự là lý do tuyệt vời để giảm "câu trả lời", đặc biệt khi không nói bất cứ điều gì không được nói trong câu hỏi: "Không thể kết bạn với thông số mẫu vì tiêu chuẩn không cho phép" –

0

Cách giải quyết duy nhất tôi có thể thấy là khá xấu xí và sử dụng CRTP:

template <typename T> 
struct CanUseAccessibleMember 
{ 
    template <typename T> 
    static const T& get(const accessible_member<T>& m) 
    { return static_cast<const T&>(m); } 

    // Etc. You can even specialize this class. 
}; 

struct ExampleOwner 
    : protected CanUseAccessibleMember<ExampleOwner> 
{ 
    // Do whatever you want with accessible members here 
    // but you have to use the get syntax 
}; 

template <typename T, typename Owner> 
class accessible_member 
{ 
    // Implement members as you did 

    friend struct CanUseAccessibleMember<Owner>; 
}; 
+0

Nếu tất cả của ctors, phương thức và toán tử của accessible_member là riêng tư (như trong câu hỏi), ExampleOwner vẫn không thể truy cập chúng. –

+0

@Fred: Bạn phải viết trình bao bọc trong lớp 'CanUseAccessibleMember' cơ sở, như' get'. Vì bạn dường như chỉ có một vài thành viên nên không sao. Đó là lý do tại sao tôi nói nó là xấu xí. –

0

Điều đó sẽ làm việc, với một chút thay đổi, dưới C++ 98 như xa như tôi có thể nhìn thấy. Nó được biên soạn mà không cần bất kỳ cảnh báo cho tôi với g++-4.1 -Wall -Wextra -pedantic -ansi -std=c++98

Chỉ cần thay đổi

friend Owner; 

để

struct Wrapper { typedef Owner type; }; 
friend class Wrapper :: type; 

(tôi đã nhận rằng câu trả lời trên Stackoverflow, câu hỏi này đã đưa ra một vài lần: Template parameter as a friend)

+0

Tôi thấy ý tưởng chung này hữu ích khi thực hiện một toán tử ('toán tử const T &') dưới dạng 'công khai'.Điều này mang lại một cách dễ dàng để đánh dấu một cái gì đó là 'có thể đọc công khai nhưng không thể ghi công khai'. tức là không cần thiết cho tất cả những điều vô nghĩa đó :-) –

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