2012-11-10 38 views
6

Tôi đang chứng kiến ​​một hành vi trong đoạn mã sau mà tôi không hiểu. Vấn đề là nếu tôi khai báo quá tải thứ hai của operator() như một trong hai điều sau đây:boost :: variant - Tại sao tham số mẫu có ưu tiên cao hơn tham số chuỗi const

bool operator()(T other) const 
bool operator()(const T &other) const 

Kết quả của chương trình là:

chuỗi

Nhưng nếu tôi sử dụng sau đây khai báo:

bool operator()(T &other) const 

Kết quả sẽ là:

loại khác

Ai đó có thể vui lòng giải thích lý do tại sao operator()(const string &other) không được gọi trong trường hợp sau?

#include "boost/variant/variant.hpp" 
#include "boost/variant/apply_visitor.hpp" 

using namespace std; 
using namespace boost; 

typedef variant<string, int> MyVariant; 


class StartsWith 
    : public boost::static_visitor<bool> 
{ 
public: 
    string mPrefix; 
    bool operator()(const string &other) const 
    { 
     cout << "string" << endl; 
     return other.compare(0, mPrefix.length(), mPrefix) == 0; 
    } 
    template<typename T> 
    bool operator()(T &other) const 
    { 
     cout << "other type" << endl; 
     return false; 
    } 
    StartsWith(string const& prefix):mPrefix(prefix){} 
}; 

int main(int argc, char **argv) 
{ 
    MyVariant v(string("123456")); 
    apply_visitor(StartsWith("123"), v); 
    return 0; 
} 

Trả lời

5

Bạn có const vấn đề ở đây.

Bạn đang chuyển không phải đối tượng const đến apply_visitor - vì vậy, không phải thành viên đối tượng const được chuyển cho khách truy cập được áp dụng. Vì vậy, trong trường hợp của bạn, nó là string& - tham chiếu đến loại chuỗi. Mẫu này khớp chính xác với mẫu:

template<typename T> 
bool operator()(T &other) const 

Vì vậy, nó được chọn. Chức năng này không phải là kết hợp chính xác - đó là bị bỏ qua:

bool operator()(const string &other) const 

Tất nhiên nếu bạn cung cấp mà nhà điều hành:

bool operator()(string &other) const 

sau đó nó sẽ được chọn, vì hàm mẫu không được xem xét trước khi mẫu một.

Vì vậy, giải pháp là: hoặc cung cấp phương pháp trong khách truy cập của bạn mà có tài liệu tham khảo chuỗi (không const) - hoặc vượt qua biến const để áp dụng ...

giải pháp đầu tiên - loại bỏ const từ chuỗi hành:

bool operator()(/*const*/ string &other) const 
//    ^^^^^^^^^ remove it 

giải pháp thứ hai - vượt qua đối tượng const:

const MyVariant& cv = v; 
apply_visitor(StartsWith("123"), cv); 
//        ^^ const object passed here 

giải pháp thứ ba - thêm specifier const để khách truy cập chung:

template<typename T> 
bool operator()(const T &other) const 
//    ^^^^^ 

Giải pháp thứ nhất và thứ ba là tốt hơn 2 - bạn nên chuyển khách truy cập nhất quán đến biến thể của bạn, const có ý nghĩa mạnh mẽ khi trình biên dịch phải chọn chức năng phù hợp.

+0

Là một loại freak, tôi sẽ nói rằng giải pháp ** 3 ** là ** tốt nhất **, as-in: ** const-correct **. Không có lý do để lấy tham số bằng tham chiếu không const nếu bạn không sửa đổi nó. –

+0

@MatthieuM. Trong trường hợp này, bạn đúng.Tôi đã không đề cập đến 'T &&' - có lẽ nó sẽ là tốt nhất - nhưng có rất nhiều bài viết SO thảo luận về sự khác biệt giữa 'T &&' và 'const T &' vì vậy tôi không muốn tạo ra hỗn hợp không cần thiết ở đây ... – PiotrNycz

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