【问题标题】:Map of strings and pointers to templated functions字符串映射和指向模板函数的指针
【发布时间】:2014-02-15 22:08:52
【问题描述】:

我正在开发 2D 游戏引擎,但我不断遇到模板问题。所以,对于这个,我有一个这样的模板函数:

template <class T>
T *S2M_CreateObject(int x, int y) {
    return new T(x, y);
}

现在,我希望游戏从文件中加载关卡数据,其中包括加载和实例化 Object 派生类,所以我制作了这样的 std::map:

map <string, Object *(*)(int x, int y)> o {
    { "warp", &S2M_CreateObject<Warp> }
};

它存储了一个字符串,我将在关卡编辑器中使用该字符串来引用一个确定的类,并将其映射到一个函数指针,该函数指针将创建该类的实例。

我希望你明白,这是我最喜欢的方法,但它不起作用。但是,如果我删除 Warp 模板说明符(Warp 是 Object 的派生类),它会起作用,但这不是目标。我知道我可以为我在游戏中定义的每个对象类型创建一个函数,但由于我正在编写游戏引擎,我无法弄清楚用户将创建多少个对象派生类,我不能指望他/她对每个功能进行编程。

还有其他方法可以做到吗?

【问题讨论】:

    标签: c++ function templates map function-pointers


    【解决方案1】:

    虽然Warp* 可以隐式转换为Object*,但指向返回Warp* 的函数的指针不能隐式转换为指向返回Object* 的函数的指针。一般来说,这种转换也不能安全地进行

    现在您的代码不起作用的原因应该很清楚了。 &amp;S2M_CreateObject&lt;Warp&gt; 的类型为 Warp* (*)(int, int),不能隐式转换为 Object* (*)(int, int)。相反,您可以让S2M_CreateObject 函数始终 返回Object*,而不管实际创建的是哪种类型:

    #include <map>
    #include <string>
    using namespace std;
    
    struct Object {
        Object() {}
        Object(int x, int y) {}
    };
    struct Warp : Object {
        Warp() {}
        Warp(int x, int y) {}
    };
    
    template <class T>
    Object* S2M_CreateObject(int x, int y) {
        return new T(x, y);
    }
    
    int main() {
        map<string, Object *(*)(int x, int y)> o {
            { "warp", &S2M_CreateObject<Warp> }
        };
    }
    

    【讨论】:

    • 谢谢,就是这样。你让我今天一整天都感觉很好!在使用指向子类的指针时,我会尽量记住这一点。
    【解决方案2】:

    感谢您之前的帮助,我可以这样做:这是某种工作结果(简化)。我将它与一个非常简单的范围函数一起使用

    //Define your template function
    template<typename Type>
    void fnRangeValue(CMyClass * poMyObject, std::string strFormat){
        Type tMyField, tMinValue, tMaxValue;
        /*Do what you have to here!*/
    }
    
    //Define a macro for your pointerFunction
    typedef void (*fnPointerFunctionRange)(CMyClass * poMyObject, std::string strFormat );
    // Define your lookup table (map)
    const std::map<std::string, fnPointerFunctionRange> ST_FORMAT_RANGE_POINTER= {
            {"UINT8",&fnRangeValue<uint8_t>},
            {"STR1UINT8",&fnRangeValue<uint8_t>},
            {"UINT16",&fnRangeValue<uint16_t>},
            {"STR2UINT16",&fnRangeValue<uint16_t>},
            {"STR4UINT16",&fnRangeValue<uint16_t>},
            {"UINT32",&fnRangeValue<uint32_t>},
            {"INT8",&fnRangeValue<int8_t>},
            {"INT16",&fnRangeValue<int16_t>},
            {"STR3INT16",&fnRangeValue<int16_t>},
            {"INT32",&fnRangeValue<int32_t>},
            {"FLT32",&fnRangeValue<float>},
            {"FLT64",&fnRangeValue<double>},
            {"STR7FL64",&fnRangeValue<double>},
            {"STR8FL64",&fnRangeValue<double>},
    };
    
    void fnRangeField(CMyClass * poMyObject){
        std::string strFormat;
        fnPointerFunctionRange poFonctionRange;
        strFormat = "UINT8";
        auto itMapRangePointer = ST_EOIIM_FORMAT_RANGE_POINTER.find(strFormat);
        if(itMapRangePointer != ST_FORMAT_RANGE_POINTER.end()){
            poFonctionRange = ST_FORMAT_RANGE_POINTER.at(strFormat);
            // Call of the right template function thanks to pointers
            poFonctionRange(poMyObject,strFormat);
        }
    }
    

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 2011-06-05
      • 1970-01-01
      相关资源
      最近更新 更多