std::function 内部初始化 class

std::function initialization inside class

我想了解 std::function 是如何工作的,但我无法编译它,我也不明白为什么。我认为这与在 class 中使用 std::function 有关,因为没有 classes(在全局范围内定义的地图)它起作用了。

这是我收到的错误消息:

functor.cc:37:9: error: could not convert ‘{{"A", ((C*)this)->C::f}, {"B", ((C*)this)->C::g}, {"C", ((C*)this)->C::h}}’ from ‘<brace-enclosed initializer list>’ to ‘std::map<std::__cxx11::basic_string<char>, std::function<bool(const std::vector<std::__cxx11::basic_string<char> >&)> >’

示例代码(没有任何意义,但它很好地代表了我遇到的问题):

#include <iostream>
#include <map>
#include <functional>
#include <vector>


class C { 
    public:
        bool f(const std::vector<std::string>& s) {
            std::cout << "F" << std::endl;
            for (auto& i : s) {
                std::cout << i << std::endl;
            }
            return true;
        }

        bool g(const std::vector<std::string>& s) {
            std::cout << "G" << std::endl;
            for (auto& i : s) {
                std::cout << i << std::endl;
            }
            return true;
        }

        bool h(const std::vector<std::string>& s) {
            std::cout << "H" << std::endl;
            for (auto& i : s) {
                std::cout << i << std::endl;
            }
            return true;
        }

        std::map<std::string, std::function<bool(const std::vector<std::string>&)> >  funcMap {
            {"A", f},
            {"B", g},
            {"C", h}
        };
};


int main() {
    std::vector<std::string> v{"mno", "pqr", "stu"};
    C c;
    c.funcMap["A"](v);
}
std::function<bool(const std::vector<std::string>&)

该函数对象类型只能包装具有签名 bool(const std::vector<std::string>&) 的函数。但是,none 尝试使用的函数具有这样的签名,因为它们是(非静态)成员函数。此外,您必须显式使用 address-of 运算符来获取指向成员函数的指针,并且名称必须完全限定,如下所示:&C::f.

您可以将 this 绑定到成员函数,这将导致具有适当签名的函数对象:

std::map<std::string, std::function<bool(const std::vector<std::string>&)> >  funcMap {
    {"A", std::bind(&C::f, this, std::placeholders::_1)},
    {"B", std::bind(&C::g, this, std::placeholders::_1)},
    {"C", std::bind(&C::h, this, std::placeholders::_1)}
                           ^ we bind this pointer to the function object
};

您也可以使用 lambda。绑定函数和 lambda 大多只是编写同一事物的两种方式。


或者您可能打算实际上只存储成员函数而不是函数对象中的对象指针。在那种情况下,您的函数对象的类型以及您调用它的方式都是错误的。这会起作用:

std::map<std::string, std::function<bool(C*, const std::vector<std::string>&)> >  funcMap {
//                                       ^ note the pointer argument for this
    {"A", &C::f},
    {"B", &C::g},
    {"C", &C::h}
};

// call
c.funcMap["A"](&c, v);
//              ^ The object on which the member function is called. 
//                It doesn't necessarily have to be the same whose funcMap is used.

在这种情况下,您并不需要 std::function。成员函数指针的映射就足够了。调用成员函数指针的语法与使用函数对象有点不同:

std::map<std::string, bool (C::*)(const std::vector<std::string>&) >  funcMap {
    {"A", &C::f},
    {"B", &C::g},
    {"C", &C::h}
};

// call
(c.*c.funcMap["A"])(v);

但是,考虑到其中 none 使用对象的状态,您还不清楚为什么需要使用成员函数。另一个简单的解决方案是首先不使用非静态函数。