C++使用模板和继承创建函数映射

C++ Creating function map using templates and inheritance

本文关键字:继承 创建 函数 映射 C++      更新时间:2023-10-16

我正在尝试使用模板创建一个通用函数映射。其思想是从这个具有特定函数指针类型的通用模板类中继承。我可以在全局工作区中注册一个函数,但我更愿意将所有函数一起收集到派生类中,并将它们注册到构造函数中。我想我差不多到了,但我遇到了一个编译错误。这是我代码的精简版本:

#include <iostream>
#include <string>
#include <map>
#include <cassert>
using namespace std; 
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef int (*F)(int);
// function factory
template <typename T>
class FunctionMap {
public: 
    void registerFunction(string name, T fp) {
        FunMap[name] = fp;
    }
    T getFunction(string name) {
        assert(FunMap.find(name) != FunMap.end());
        return FunMap[name];
    }
private:
    map<string, T> FunMap;
};
// specific to integer functions 
class IntFunctionMap : public FunctionMap<F> {
public:
    int f2(int x) { return 2 * x; }
    int g2(int x) { return -3 * x; }
    IntFunctionMap() {
        registerFunction("f", f); // This works
        registerFunction("f2", f2); // This does not
    }
};
int main()
{
     FunctionMap<F> fmap; // using the base template class directly works
     fmap.registerFunction("f", f);
     F fun = fmap.getFunction("f");
     cout << fun(10) << endl; 
     return 0;
}

我得到的错误是:

templatefunctions.cpp: In constructor ‘IntFunctionMap::IntFunctionMap()’:
templatefunctions.cpp:33: error: no matching function for call to     ‘IntFunctionMap::registerFunction(const char [3], <unresolved overloaded function type>)’
templatefunctions.cpp:15: note: candidates are: void FunctionMap<T>::registerFunction(std::string, T) [with T = int (*)(int)]

Juan的答案是正确的:成员函数有一个隐式的第一个参数,它是指向它们所属类型的指针。代码编译失败的原因是映射支持类型为int (*)(int)的函数指针,但f2的类型是int (IntFunctionMap::*)(int)

在这里显示的特定情况下,可以使用实现类型擦除的std::function将自由函数和成员函数表示为同一类型。然后你就可以做你想做的事情了。注意:这需要C++11。

#include <iostream>
#include <string>
#include <map>
#include <cassert>
#include <function>
#include <bind>
using namespace std; 
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef std::function<int (int)> F;
// function factory
template <typename T>
class FunctionMap {
public: 
    void registerFunction(string name, T fp) {
        FunMap[name] = fp;
    }
    T getFunction(string name) {
        assert(FunMap.find(name) != FunMap.end());
        return FunMap[name];
    }
private:
    map<string, T> FunMap;
};
// specific to integer functions 
class IntFunctionMap : public FunctionMap<F> {
public:
    int f2(int x) { return 2 * x; }
    int g2(int x) { return -3 * x; }
    IntFunctionMap() {
        registerFunction("f", f); // This works
        registerFunction("f2", std::bind(&f2, this, _1)); // This should work, too!
    }
};
int main()
{
     FunctionMap<F> fmap; // using the base template class directly works
     fmap.registerFunction("f", f);
     F fun = fmap.getFunction("f");
     cout << fun(10) << endl; 
     return 0;
}