Overloaded statement with std :: function parameter

I am working on a multi-type card holder. It works with all primitive types, as well as with structures, for example. Point. However, if I want to add std :: function as another supported type (used for callbacks), the compiler complains:

MT.cpp: 426: 15: no viable overloaded '='

MT.h: 31: 7: candidate function (implicit copy operator) is not viable: unknown conversion from '(lambda at MT.cpp: 426: 17)' to 'const sharkLib :: MT' for 1st argument

MT.h: 31: 7: Candidate function (implicit move assignment operator) is not viable: no known conversion from '(lambda to MT.cpp: 426: 17)' to 'sharkLib :: MT' for the 1st argument

I actually do not overload the = operator, but instead overload [] selected constructor with a supported type.

.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]; } 

Using

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

The last line is an error with an error.

+5
source share
2 answers

The problem is that you are trying to use a double conversion sequence:

  • From lambda function to std::function<void(Ref*)>
  • From std::function<void(Ref*)> to MT

On this path, you need to remove the need for double conversion using

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

If you want to support conversion from function type to MT , you will need an MT constructor that directly accepts the function type. Assuming none of your other constructors are written using an unlimited template, you can simply add

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

If you already use the template without restrictions for another type, you will need to use suitable conditions, for example. std::is_convertible<Fun, std::function<void(Ref*)>>::value along with a suitable SFINAE approach to remove the corresponding constructor (s) from the overload set.

+4
source

Ok, Chris inspired me, and this solution:

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

All Articles