2010-07-29 41 views
6

Tôi có một lớp C++ templated đó cho thấy nhiều một số phương pháp, ví dụ nhưphương pháp Thêm vào mẫu chuyên môn

template<int X, int Y> 
class MyBuffer { 
public: 
    MyBuffer<X,Y> method1(); 
}; 

Bây giờ, tôi muốn để lộ phương pháp bổ sung cho lớp này nếu X == Y. Tôi đã làm điều này bằng cách phân loại MyBuffer,

template<int X> 
class MyRegularBuffer : public MyBuffer<X,X> { 
public: 
    MyRegularBuffer method2(); 
}; 

Bây giờ, vấn đề là tôi muốn có thể làm ví dụ

MyRegularBuffer<2> buf = ... 
MyRegularBuffer<2> otherBuf = buf.method1().method2(); 

Nhưng tôi không chắc chắn cách thực hiện việc này. Tôi đã cố gắng để nghĩ về các nhà xây dựng bản sao, các nhà khai thác chuyển đổi, vv, nhưng kỹ năng C++ của tôi là tiếc là một chút gỉ.

EDIT: Tôi nên thêm rằng việc tạo ra các đối tượng này là tương đối rẻ (và cũng có thể, nó sẽ không xảy ra rất nhiều), có nghĩa là nó sẽ là OK để làm một cái gì đó như thế này:

MyRegularBuffer<2> buf = ... 
MyRegularBuffer<2> temp = buf.method1(); // Implicit conversion 
MyRegularBuffer<2> otherBuf = temp.method2(); 

Các câu hỏi là, làm cách nào tôi có thể xác định chuyển đổi như vậy. Các nhà điều hành chuyển đổi cần phải được trong MyBuffer, tôi nghĩ, nhưng tôi muốn nó có sẵn chỉ khi X == Y.

+1

hoàn toàn không thể hiểu được. Ví dụ, bạn nói về "toán tử chuyển đổi", nhưng không có gì. Đăng một số mã thực. –

+0

@Neil, tôi nghĩ người dùng đã hỏi một câu hỏi chính hãng với khả năng tốt nhất của họ. Và tôi nghĩ tôi hiểu nó một chút. –

+0

@Aaron Trong trường hợp đó, hãy chia sẻ sự hiểu biết của bạn. –

Trả lời

5

Bạn không cần một lớp riêng biệt để đại diện cho hành vi đặc biệt. Chuyên môn từng phần cho phép bạn xử lý một số trường hợp MyBuffer < X, Y > đặc biệt và cung cấp cho họ các phương pháp bổ sung.

Giữ khai ban đầu của bạn của mybuffer < X, Y > và thêm này:

template<int Y> 
class MyBuffer<Y, Y> { 
public: 
    MyBuffer<Y,Y> method1(); 
    MyBuffer<Y,Y> method2(); 
}; 

MyBuffer<1,2> m12; m12.method2(); // compile fail, as desired, as it doesn't have such a method because 1 != 2 
MyBuffer<2,2> m22; m22.method2(); // compile success 

Edit: dòng cuối cùng của tôi là không phải là rất hữu ích sau khi tất cả, như đã chỉ ra bởi Georg trong các ý kiến, vì vậy tôi đã xóa chúng.

+1

Nhược điểm duy nhất là phương thức1() phải được triển khai lại trong MyBuffer , nếu không trình biên dịch sẽ phàn nàn về một phương thức chưa biết khi bạn cố gắng gọi MyBuffer :: method1(). AFAIK, không có cách nào để có MyBuffer :: method1() ủy nhiệm việc triển khai của nó cho MyBuffer :: method1() mà không chỉ định các tham số mẫu khác nhau trong đó X! = Y. –

+0

Bắt nguồn từ 'MyBuffer' sẽ không hoạt động - nó không không biết lớp dẫn xuất và do đó không thể trả về kiểu thích hợp từ 'method1()'. –

+0

@Georg, tôi không hiểu. Bạn có thể cụ thể hơn về dòng nào sẽ thất bại không? Tôi đã biên dịch mã của tôi và nó hoạt động. Nhưng tôi phải thừa nhận tôi đã sao chép dòng cuối cùng không đúng về "class MyRegularBuffer". Sẽ cập nhật ngay bây giờ. –

1

Có thể thực hiện những gì bạn muốn nếu method1method2 trả lại tham chiếu đến *this. Nếu không, bạn sẽ cần thực hiện chuyển đổi hoặc tạo method1 ảo.

+0

Thậm chí nếu method1() trả về giá trị này, bạn vẫn không thể gọi method2() từ giá trị trả về của nó, bởi vì method2() không phải là một phần của giao diện MyBuffer . – wilhelmtell

+0

Bạn có thể vui lòng xây dựng trên phương pháp tiếp cận ảo không? Tôi không chắc tôi có được ... Vấn đề tôi đang phải đối mặt là hợp đồng, việc thực hiện sẽ giống nhau (đối tượng là giống hệt nhau trong bộ nhớ nếu X == Y, vì vậy tôi chỉ có thể làm một reinterpretation). – Krumelur

+0

wilhelmtell, vâng, chính xác những gì tôi muốn nói. Bạn đã nhanh hơn :) – Krumelur

1

Bí quyết là phải có một MyRegularBuffer::method1 mà các cuộc gọi MyBuffer::method1, sau đó là một cách để chuyển đổi các kết quả MyBuffer<X,X> thành một MyRegularBuffer<X>:

template<int X> 
class MyRegularBuffer : public MyBuffer<X,X> 
{ 
public: 

    MyRegularBuffer<X>() 
    {} 

    MyRegularBuffer<X>(MyBuffer<X,X>) 
    { 
    // copy fields, or whatever 
    } 

    MyRegularBuffer<X> method2(); 

    MyRegularBuffer<X> method1() 
    { 
    MyRegularBuffer<X> ret(MyBuffer<X,X>::method1()); 
    return(ret); 
    } 
}; 
+0

Cảm ơn bạn. Vâng, đây là một ý tưởng hay, nhưng trong trường hợp của tôi, nó không thêm bất cứ thứ gì vào giải pháp @Aaron McDaid, trong đó tôi phải thực hiện lại method1 (phương thức1 thực sự là một số phương thức). – Krumelur

3

tôi muốn đi cho CRTP đây:

template<int X, int Y, class Derived> 
struct MyBufferBase { 
    // common interface: 
    Derived& method1() { return *static_cast<Derived*>(this); } 
}; 

template<int X, int Y> 
struct MyBuffer : MyBufferBase<X, Y, MyBuffer<X,Y> > { 
    // basic version 
}; 

template<int X> 
struct MyRegularBuffer : MyBufferBase<X, X, MyRegularBuffer<X> > { 
    // extended interface: 
    MyRegularBuffer& method2() { return *this; } 
}; 
+0

+1 Cảm ơn bạn đã nhắc tôi về điều đó. –

+0

Cảm ơn vì điều đó. Đó hoàn toàn là một ý tưởng hay. – Krumelur

+0

Tôi đã đánh dấu là câu trả lời nếu tôi có thể đưa ra nhiều hơn một câu trả lời, nhưng ngay bây giờ giải pháp của Aaron McDaid thực sự rơi ra khá tốt, vì phương pháp của tôi khá mỏng (nó là lớp bọc). – Krumelur

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