c++ - 无法从映射中恢复指向成员函数的指针

标签 c++ dictionary pointer-to-member

我的计划是评估和表征时间序列信息。数据可能具有大约 90 种不同的信号。每个信号都有一个独特的公式和一组不同的参数和值。这段代码和我的问题是从配置文件加载这些值。编译器是 VS 2010。

每个信号都由一个类表示,这里用类 TRI{} 进行说明,并且每个这样的类都派生自类 SIGNAL{}。 SIGNAL 包含一个静态映射(我的实际代码使用 unordered_map),它用于保存成对的信号名称和指向信号成员函数的指针,该成员函数将参数值分配给它们各自的变量。我的问题是操纵这个成员函数。

显然,在此代码 &TRI::load_cfg_vals 中,信号成员函数的地址从未存储在映射 sig_map 中。所以从调试器看来。当我尝试调用 TRI 信号的加载函数时,编译器说我正在尝试调用不是函数的东西。请查看我的一些失败尝试的代码。

我怎样才能让它与这些对象一起工作?我真的不知道问题出在哪里,更糟糕的是,我不知道我不了解如何使用 STL 或 C++。

(我准备放弃了。我正在考虑另一种更像 C 的方法。使用映射,将每个信号名称与一个唯一的整数相关联(已经在实际代码中 - 它们都表示作为唯一的单个位。将 void 指针数组的每个元素加载到信号的加载函数的地址,其整数值是该元素的数组中的偏移量。我选择的第一种方法,下面的代码,似乎更容易维护,更高级一点。)

在发布这篇文章之前,我研究了很多问题和答案,其中包括

member function pointers and inheritance

C++ Map of string and member function pointer

C++ pointers to member functions

C++ Call pointer to member with a map from a const function

TIA

#include <iostream>
#include <map>
#include <string>
using namespace std;

typedef std::map< string, void *>    ARG_MAP;
typedef ARG_MAP::iterator            ARG_ITR;
typedef std::pair < ARG_ITR, bool>   ARG_PAIR;

// forward decl
class SIGNAL;

typedef int (SIGNAL::*PF)(void);
typedef std::map< string, PF>          SIG_MAP;
typedef SIG_MAP::iterator              SIG_MAP_ITR;
typedef std::pair < SIG_MAP_ITR, bool> SIG_MAP_PAIR;

class SIGNAL
{
public:
    ARG_MAP             arg_map;
    ARG_ITR             ai;
    ARG_PAIR            ap;

    static SIG_MAP      sig_map;

    SIGNAL() {};
    ~SIGNAL(){};
    virtual int calc() = 0;
    virtual int load_cfg_vals() = 0;
};

// tried globals versus members, no difference
SIG_MAP       SIGNAL::sig_map;
SIG_MAP_ITR   smi;
SIG_MAP_PAIR  smp;

class TRI: public SIGNAL
{
public:
    float f;

    int calc(){return 1;}
    int load_cfg_vals()
    {
        // the f arg
        ai = arg_map.find("f_descriptive_name");
        *(float *) ai->second = (float)12.005;

        return 1;
    };

    TRI()
    {
        // associates the TRI class function 'load_cfg_vals()' with the
        // signal name 'tri'
        SIGNAL::sig_map.insert(std::make_pair ("tri", 
                                               (PF) &TRI::load_cfg_vals));
        // this apparently doesn't load the address of the function, see below

        //sig_map.insert(std::make_pair ("tri",&TRI::load_cfg_vals));
        // fails with error C2440: 'initializing' : cannot convert from 
        // from 'int (__thiscall TRI::* )(void)' to 'PF '

        //SIGNAL::sig_map.insert( map<string, PF>::value_type("tri", 
        //      dynamic_cast< & SIGNAL::load_cfg_vals> (&TRI::load_cfg_vals) ));
        // C2059: syntax error : '&'
        // so, maybe this is right but for my lack of understanding of what
        // types are involved/required here

        // contains the list of descriptive names of the signal's parameters
        // and the addresses of the variables that hold the parameters'values
        arg_map.insert(std::make_pair ("f_descriptive_name", (void*) &f));
    };
    ~TRI(){};
};


int main(void)
{
    TRI    tri;
    PF     pf;
    char * input_str = "tri";  // this and the names of the many other
                               // signals would be read from the cfg file

    // while there are still more signal names to read in
    // while( fscanf(...input_str...) {  removed
        if( (smi = tri.sig_map.find (input_str)) == tri.sig_map.end())
            cout << "'" << input_str << "' not found\n";
        else
        {
            // smi->second is supposed to contain the function of the
            // signal class that is to properly interpret and handle
            // the list of values stored in the cfg file 
            //(smi->second)();
            // error C2064: term does not evaluate to a function taking
            //              0 arguments

            string s = smi->first;  // OK
            pf = (PF)smi->second;
            // Doesn't contain the address of the function that was
            // loaded, above, in TRI().  The debugger identifies
            // it as TRI::`vcall'{4}', I don't know what that is.
            // Debugger emits the entire type of the operator and 
            // its return value, but I can't get it to format for
            // proper display here.  If someone wants to see it, 
            // I'll supply it unformatted.

            //int z = (*pf)();
            // error C2064: term does not evaluate to a function taking 0 
            // arguments

            // the following don't help the value in pf.  same error C2064 or 
            // complaints about improper use of the casts
            //pf = reinterpret_cast <int (__thiscall *)(void)>(smi->second);
            //pf = static_cast <int (__thiscall *)(void)>(smi->second);

        }
    // } // end while   removed
  return 1;
}

最佳答案

保持简单,而不是尝试将指向成员的指针类型插入到 map 中,而只是尝试转换为 PF 类型:

PF pf = &TRI::load_cfg_vals;

由于 an answer to one of the questions you linked to 中解释的原因,这无法编译,就像这个简化的例子没有:

struct A {
  virtual int f() = 0;
};

struct B : A {
  int f() { return 0; }
};

int (A::*pf)() = &B::f;

因此,如果它不能编译,那么在更复杂的情况下依赖它的版本也不会编译。

为什么你不能这样做:

    SIGNAL::sig_map.insert(std::make_pair ("tri", 
                                           &SIGNAL::load_cfg_vals));

&SIGNAL::load_cfg_vals 的类型与您尝试存储在 map 中的类型相同,因此可以正常工作。

这不会编译,因为 dynamic_cast 的模板参数必须是类型,而不是指向成员的指针:

    SIGNAL::sig_map.insert( map<string, PF>::value_type("tri", 
          dynamic_cast< & SIGNAL::load_cfg_vals> (&TRI::load_cfg_vals) ));

dynamic_cast 用于将指针转换为多态类型,而不是指向成员的指针类型,这将改为编译,但最好避免强制转换:

    SIGNAL::sig_map.insert( map<string, PF>::value_type("tri", 
          static_cast<PF> (&TRI::load_cfg_vals) ));

此外,为什么您的所有类型和 typedef 都是 ALL_CAPS?别喊了,ALL_CAPS 用于宏,不要那样命名你的类型。

关于c++ - 无法从映射中恢复指向成员函数的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18623035/

相关文章:

c++ - 为什么要在 C 和 C++ 项目中创建包含/目录?

c++ - 如果嵌套对象具有相同的地址,编译器如何区分它们?

c++ - 获取行验证

python: filter() 可迭代,计算已过滤和未过滤的项目

c++ - 类成员函数指针作为类成员

c++ - 如何将 MQseries 原因代码转换为字符串?

dictionary - Prolog:如何将字典的负索引转换为最大索引的正后继者?

c++ - 将 void 替换为模板方法的参数

c++ - 无法将类成员函数传递给另一个函数 (std::thread::thread)

ios - 无法在深度嵌套的数据结构上下标错误