2012-11-07 41 views
14

Tôi đã khai báo một số boost::variant chấp nhận ba loại: string, boolint. Đoạn mã sau cho thấy biến thể của tôi chấp nhận const char* và chuyển đổi nó thành bool. Có phải hành vi bình thường đối với boost::variant để chấp nhận và chuyển đổi các loại không có trong danh sách của nó?boost :: variant - tại sao "const char *" được chuyển thành "bool"?

#include <iostream> 
#include "boost/variant/variant.hpp" 
#include "boost/variant/apply_visitor.hpp" 

using namespace std; 
using namespace boost; 

typedef variant<string, bool, int> MyVariant; 

class TestVariant 
    : public boost::static_visitor<> 
{ 
public: 
    void operator()(string &v) const 
    { 
     cout << "type: string -> " << v << endl; 
    } 
    template<typename U> 
    void operator()(U &v)const 
    { 
     cout << "type: other -> " << v << endl; 
    } 
}; 

int main(int argc, char **argv) 
{ 
    MyVariant s1 = "some string"; 
    apply_visitor(TestVariant(), s1); 

    MyVariant s2 = string("some string"); 
    apply_visitor(TestVariant(), s2); 

    return 0; 
} 

đầu ra:

loại: khác -> 1
loại: string -> một số chuỗi

Nếu tôi loại bỏ các kiểu bool từ MyVariant và thay đổi nó như thế này:

typedef variant<string, int> MyVariant; 

const char* không được chuyển đổi thành bool nữa. Lần này nó chuyển đổi sang string và đây là sản phẩm mới:

loại: string -> một số chuỗi
loại: string -> một số chuỗi

Điều này cho thấy rằng variant cố gắng để chuyển đổi các loại trước tiên là bool và sau đó đến string. Nếu việc chuyển đổi loại là điều không thể tránh khỏi và luôn luôn xảy ra, có cách nào để chuyển đổi cho string mức độ ưu tiên cao hơn không?

Trả lời

10

Tôi không nghĩ rằng đây là bất cứ điều gì đặc biệt để làm với , đó là về nhà xây dựng được chọn bởi độ phân giải quá tải. Điều tương tự cũng xảy ra với một chức năng quá tải:

#include <iostream> 
#include <string> 

void foo(bool) { 
    std::cout << "bool\n"; 
} 

void foo(std::string) { 
    std::cout << "string\n"; 
} 

int main() { 
    foo("hi"); 
} 

đầu ra:

bool 

Tôi không biết một cách để thay đổi những gì nhà xây dựng một biến thể có [sửa: như James nói, bạn có thể viết một lớp khác sử dụng Biến thể trong việc thực hiện nó. Sau đó, bạn có thể cung cấp một hàm tạo const char* làm điều đúng.]

Có thể bạn có thể thay đổi các loại trong Biến thể. Một ví dụ quá tải:

struct MyBool { 
    bool val; 
    explicit MyBool(bool val) : val(val) {} 
}; 

void bar(MyBool) { 
    std::cout << "bool\n"; 
} 

void bar(const std::string &) { 
    std::cout << "string\n"; 
} 

int main() { 
    bar("hi"); 
} 

đầu ra:

string 

Đáng tiếc là bây giờ bạn phải viết bar(MyBool(true)) thay vì foo(true). Thậm chí tệ hơn trong trường hợp của biến thể của bạn với string/bool/int, nếu bạn chỉ cần thay đổi nó thành biến thể string/MyBool/int thì MyVariant(true) sẽ gọi hàm tạo int.

+6

Để hoàn thành giải thích của bạn: có chuyển đổi tiềm ẩn từ bất kỳ loại con trỏ nào thành 'bool' và chuyển đổi ngầm định luôn được chọn tùy theo chuyển đổi do người dùng xác định. (Việc chuyển đổi 'char *' thành 'std :: string' được tính là do người dùng định nghĩa.) Đối với việc thay đổi các hàm tạo, bạn có thể bọc lớp đó trong một lớp khác hoặc lấy ra từ lớp đó. Tùy thuộc vào ngữ cảnh, một trong những điều này có thể hoặc có thể không phù hợp; cả hai đều có một số nhược điểm. –

+0

Tôi nghĩ rằng một giải pháp là xóa 'bool' khỏi' MyVariant' và sử dụng giá trị 0 và 1 để thay thế. – Meysam

+0

@Meysam: vâng. Tôi nghĩ về việc giới thiệu điều đó, nhưng sau đó tôi nghĩ bạn có thể muốn một 'MyVariant' được khởi tạo với' 0' khác với 'MyVariant' được khởi tạo với' false'. Nếu không sao cho chúng giống nhau, chỉ cần xóa 'bool'. Nếu họ có ý nghĩa khác nhau, nó không phải là đơn giản. –

9

Điều này không liên quan gì đến boost::variant, nhưng với thứ tự trong đó C++ chọn chuyển đổi để áp dụng. Trước khi cố gắng sử dụng chuyển đổi do người dùng xác định (hãy nhớ rằng std::string là lớp do người dùng xác định cho mục đích này), trình biên dịch sẽ thử chuyển đổi được tích hợp sẵn.Không có built-in chuyển đổi từ const char* để int, nhưng theo §4.12 trong tiêu chuẩn:

Một prvalue của [...] con trỏ [...] loại có thể được chuyển đổi sang một prvalue loại bool.

Vì vậy, trình biên dịch vui vẻ chuyển đổi của bạn const char* đến một bool và không bao giờ được xem xét chuyển đổi nó vào một std::string.

+0

Điều này chỉ cần bit tôi ngày hôm nay với một cặp phương pháp quá tải, một trong đó đã một 'bool', một khác' const std :: string & '. Không may! – davidbak

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