使用std :: function参数重载运算符

Per*_*com 5 c++ lambda overloading operator-overloading c++11

我正在研究多种类型的地图持有者.它适用于所有原始类型,也适用于结构,例如Point.但是,如果我想将std :: function添加为另一个受支持的类型(用于回调),那么编译器会抱怨:

MT.cpp:426:15:没有可行的重载'='

MT.h:31:7:候选函数(隐式复制赋值运算符)不可行:第一个参数没有从'(lambda at MT.cpp:426:17)'到'const sharkLib :: MT'的已知转换

MT.h:31:7:候选函数(隐式移动赋值运算符)不可行:第一个参数没有从'(lambda at MT.cpp:426:17)'到'sharkLib :: MT'的已知转换

我实际上并不重载=运算符,而是[]使用每个受支持类型的专用构造函数重载.

.H

protected: 
    map<string,MT> valueMap;

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

的.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];
}
Run Code Online (Sandbox Code Playgroud)

用法

MT mt;

mt["int"] = 1;
mt["ccb"] = [](Ref *){ CCLOG("Pressed"); };
Run Code Online (Sandbox Code Playgroud)

最后一行是有错误的.

Die*_*ühl 4

问题是您正在尝试使用双重转换序列:

  1. 从 lambda 函数到std::function<void(Ref*)>
  2. std::function<void(Ref*)>MT

解决这个问题的方法是消除双重转换的需要,使用

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

如果您想支持从函数类型到函数类型的转换,则MT需要一个MT直接采用函数类型的构造函数。假设您的其他构造函数都不是使用不受约束的模板编写的,您可以添加

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

如果您已经使用另一种类型的无约束模板,则需要使用合适的条件,例如std::is_convertible<Fun, std::function<void(Ref*)>>::value,与合适的 SFINAE 方法一起从重载集中删除相应的构造函数。