1

私のプログラムは、時系列情報を評価して特徴付けることです。データが持つ可能性がある約 90 の異なる信号があります。各信号には、独自の式と、パラメーターと値の個別のセットがあります。このコードとそれに関する私の問題は、構成ファイルからこれらの値をロードするためのものです。コンパイラはVS2010です。

各シグナルはクラスによって表され、ここではクラス TRI{} で示され、そのような各クラスはクラス SIGNAL{} から派生します。SIGNAL には静的マップが含まれています (私の実際のコードでは unordered_map を使用しています)。これは、シグナル名とパラメーター値をそれぞれの変数に割り当てるシグナルのメンバー関数へのポインターのペアを保持するためのものです。私の問題は、このメンバー関数を操作することです。

どうやら、このコード &TRI::load_cfg_vals 内のシグナルのメンバー関数のアドレスは、マップ sig_map に格納されることはありません。デバッガーからのようです。TRI シグナルのロード関数を呼び出そうとすると、関数ではないものを呼び出そうとしているとコンパイラが言います。私の失敗した試みのいくつかについては、コードを参照してください。

これをこれらのオブジェクトで動作させるにはどうすればよいですか? 何が問題なのか本当にわかりません。さらに悪いことに、STL や C++ の使用方法について何が理解できていないのかもわかりません。

(私はあきらめる準備ができています。代替の、より C に似たアプローチを検討しています。マップを使用して、各信号名を一意の整数に関連付けます (既に実際のコードで - それらはすべて一意の単一として表されます)。整数値がその要素の配列へのオフセットであるシグナルのロード関数のアドレスを使用して、void ポインターの配列の各要素をロードします. 私が選択した最初の方法である以下のコードは、維持しやすいように見えました.もう少しレベルが高い。)

これを投稿する前に私が研究した多くの質問と回答の中には、

メンバ関数ポインタと継承

文字列とメンバー関数ポインターの C++ マップ

メンバー関数への C++ ポインター

C++ const 関数からのマップを使用してメンバーへのポインターを呼び出す

ティア

#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;
}
4

1 に答える 1

0

そのメンバーへのポインター型を挿入しようとする代わりに、型へmapの変換を試みるだけで、単純にしてくださいPF

PF pf = &TRI::load_cfg_vals;

リンク先の質問の 1 つに対する回答で説明されている理由により、これはコンパイルされません。

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 はマクロ用です。型にそのような名前を付けないでください。

于 2013-09-04T21:14:09.547 に答える