2016-08-28 47 views
5

Tôi đang làm việc trên bộ giữ bản đồ nhiều loại. Nó hoạt động với tất cả các kiểu nguyên thủy và cũng với các cấu trúc, ví dụ: Điểm. Tuy nhiên, nếu tôi muốn thêm std :: chức năng như một loại hỗ trợ (sử dụng cho callbacks) sau đó trình biên dịch phàn nàn:toán tử quá tải với std :: tham số chức năng

MT.cpp: 426: 15: Không khả thi quá tải '='

MT .h: 31: 7: Chức năng ứng cử viên (toán tử gán bản sao ngầm) không thể thực hiện được: không được biết chuyển đổi từ '(lambda at MT.cpp: 426: 17)' thành 'const sharkLib :: MT' cho đối số thứ nhất

MT.h: 31: 7: Chức năng ứng cử viên (di chuyển ẩn toán tử gán) không thể thực hiện được: không có chuyển đổi đã biết từ '(lambda a t MT.cpp: 426: 17)' thành 'sharkLib :: MT' cho lập luận 1st

Tôi không thực sự quá tải = điều hành nhưng thay vì quá tải [] với nhà xây dựng dành riêng cho mỗi loại được hỗ trợ.

.h

protected: 
    map<string,MT> valueMap; 

public: 
    MT (int value); 
    MT (std::function<void(Ref*)> ccb); 
    virtual MT& operator[] (const char* key); 

cpp

MT::MT (int value) 
{ 
    this->type = ValueType::intValue; 
    this->value.int_ = value; 
} 

MT::MT (std::function<void(Ref*)> value) 
{ 
    this->type = ValueType::ccbValue; 
    this->value.ccb_ = value; 
} 

MT& MT::operator[] (const char* key) 
{ 
    return this->valueMap[key]; 
} 

sử dụng

MT mt; 

mt["int"] = 1; 
mt["ccb"] = [](Ref *){ CCLOG("Pressed"); }; 

dòng cuối cùng này là một với lỗi.

+1

Có thể trả lời ở đây: http: // stackoverflow.com/questions/13358672/how-to-convert-a-lambda-to-an-stdfunction-sử dụng-templates – Chris

+0

Tôi có dám hỏi tại sao ctors và 'operator []' có cùng kiểu không? – Yakk

Trả lời

4

Vấn đề là bạn đang cố gắng sử dụng một chuỗi chuyển đổi kép:

  1. Từ chức năng lambda để std::function<void(Ref*)>
  2. Từ std::function<void(Ref*)> đến MT

Trên đường xung quanh đó là để loại bỏ sự cần thiết của việc chuyển đổi kép, sử dụng

mt["cast via function"] = static_cast<std::function<void(Ref*)>([](Ref*){ /*...*/ }); 
mt["cast via MT"] = MT([](Ref*){ /*...*/ }); 

Nếu bạn muốn hỗ trợ việc chuyển đổi từ một loại chức năng để MT bạn cần một constructor của MT mà trực tiếp có chức năng kiểu. Giả sử không có nhà thầu khác của bạn được viết bằng cách sử dụng một mẫu không bị giới hạn, bạn chỉ có thể thêm

template <typename Fun> 
MT::MT(Fun&& fun) 
    : type(ValueType::ccbValue) { 
    this->value.ccb = std::forward<Fun>(fun); 
} 

Nếu bạn đang sử dụng một mẫu không bị giới hạn đối với một loại bạn cần phải sử dụng các điều kiện phù hợp, ví dụ std::is_convertible<Fun, std::function<void(Ref*)>>::value, cùng với phương pháp SFINAE phù hợp để loại bỏ (các) nhà xây dựng tương ứng khỏi bộ quá tải.

+0

Tại sao không bao gồm dòng sfinae trong trình xây dựng của bạn một cách rõ ràng? – Yakk

+0

@Yakk: nếu người xây dựng là người duy nhất có mẫu không bị giới hạn thì không cần thiết và nếu nó không phải là không đủ như người xây dựng khác sẽ cần phải được xử lý với trường hợp ngược lại. Vì vậy, nó có vẻ vô nghĩa bao gồm nó. –

+1

'MT const &&' và 'MT &' thích 'Fun &&' to 'MT &&' hoặc 'MT const &' no? Ngoài ra, các thông báo lỗi tốt hơn. [ví dụ trực tiếp] (http://coliru.stacked-crooked.com/a/add8adee5cf29d93). Về cơ bản bạn không bao giờ nên có một ctor chuyển tiếp hoàn hảo một đối số không được bảo vệ bởi SFINAE. – Yakk

2

Ok, Chris cảm hứng cho tôi và đây là giải pháp:

typedef std::function<void(Ref*)> ClickCallback; 
... 
    MT (ClickCallback ccb); 
... 
mt["ccb"] = (ClickCallback) [](Ref *){ CCLOG("Pressed "); };; 
+1

Cast kiểu c rõ ràng là một ý tưởng tồi nói chung. Và bạn không cần nó. – Yakk

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