2016-11-03 17 views
6

Để bắt đầu, tôi có một cái gì đó như thế này:C++: Reference/con trỏ đến biến thành viên như mẫu tham số

class Test { 
    std::vector<int> a, b; 
    void caller(...) { callee(...); } 
    void callee(...) { /* Do stuff with 'a' */ } 
} 

Những gì tôi muốn là phải có một chức năng mà không chính xác giống như callee nhưng đối với vector b. Để thực hiện điều này, có hai giải pháp rõ ràng:

  • Vượt qua vector a hoặc b làm đối số. Tuy nhiên, callee là một hàm đệ quy có thể đi cho hàng trăm cuộc gọi và truyền các vectơ làm đối số sẽ chỉ là phí trên không cần thiết.
  • Sao chép hàm callee và sử dụng vector b, đây sẽ là giải pháp thay thế tốt nhất, mặc dù thực tế là callee là một chức năng khá dài và tôi sẽ có nhiều mã trùng lặp.

Ra khỏi tò mò, tôi đã đi tìm kiếm các phần mẫu và tôi nhận thấy rằng có thể được sử dụng cho

lvalue reference type

pointer type

pointer to member type

Vì vậy, tôi đã cố gắng để làm điều này:

class Test { 
    std::vector<int> a, b; 
    void caller(...) { callee<a>(...); } 
    template <std::vector<int> &x> void callee(...) { /* Do stuff with 'x' */ } 
} 

nhưng tôi nhận

error: use of ‘this’ in a constant expression

Có cách nào để đạt được điều này hoặc bằng cách tham chiếu ence hoặc một con trỏ?

Bằng cách này, những gì tôi muốn có thể được xem như là một chức năng-scoped #define

+0

"và chuyển vectơ làm đối số sẽ chỉ là phí không cần thiết" Tôi không tin rằng bạn thậm chí sẽ nhận thấy "phí" khi bạn chuyển vectơ bằng tham chiếu hoặc con trỏ. –

+0

Vâng, vâng. Nhưng tôi sẽ lựa chọn không cho giải pháp thứ hai và không có bất kỳ chi phí nào cả. – gmardau

+0

Nếu bạn muốn sử dụng một mẫu như vậy một cách hạn chế, bạn muốn làm 'template ' và bất cứ nơi nào bạn sử dụng kiểu, chấp nhận một 'T &' - nếu bạn đặc biệt cần ngăn chặn nó được sử dụng để nói, 'std: : vector 'sau đó sử dụng' std :: enable_if' cho không khớp. – Olipro

Trả lời

3

Mảng và thậm chí cả tuples, nhưng không có tình yêu dành cho các thành viên cũ tốt?

class Test { 
    std::vector<int> a, b; 

    void caller(/*...*/) { callee<&Test::a>(/*...*/); } 

    template <std::vector<int> Test::*vec> 
    void callee(/*...*/) { /* Do stuff with `(this->*vec)` */ } 
}; 
2

Đơn giản chỉ cần sử dụng một mặt tiền:

class Test { 
    std::vector<int> a, b; 
    void caller_a(...) { callee(a); } 
    void caller_b(...) { callee(b); } 
    void callee(std::vector<int> &a_or_b, ...) { 
    } 
} 

callee() sẽ tham khảo thông số của nó, mà sẽ được thông qua tại như một hoặc thành viên lớp khác.

+0

Đó là những gì tôi đã đề cập trong giải pháp viên đạn đầu tiên. – gmardau

4

Bạn không thể sử dụng tham chiếu đến thành viên dữ liệu làm đối số mẫu: mẫu là thời gian biên dịch và giá trị this không được biết cho đến khi chạy. Nói cách khác, bạn cần có một phiên bản riêng biệt (mã nhị phân riêng) cho từng đối tượng thời gian chạy loại Test.

gì bạn thể làm là thay thế ab với một mảng, và templatise callee bởi chỉ số vào mảng này:

class Test { 
    std::array<std::vector<int>, 2> ab; 
    void caller(...) { callee<0>(...); } 
    template <size_t idx> 
    void callee(...) { /* Do stuff with 'ab[idx]' */ } 
} 

Bằng cách này, bạn sẽ có được chỉ có hai sự khởi tạo của callee (một cho 0 và một cho 1), với việc lập chỉ mục được thực hiện (hoặc ít nhất là doable) tại thời gian biên dịch.

1

Trong logic tương tự như câu trả lời @ Angew, bạn cũng có thể sử dụng std :: tuple, và nó khá thú vị như với tuple bạn cũng có thể sử dụng loại khác nhau của các container trong chức năng callee của bạn:

class Test { 
    std::tuple<std::vector<int>, std::list<int> > ab; 
    void caller(...) { callee<0>(...); } 
    template <size_t idx> 
    void callee(...) { 
    ... 
    auto aIt = std::get<idx>(ab).begin(); // gets either the vector or the list depending on template value 
    ... 
    } 
} 
Các vấn đề liên quan