web-dev-qa-db-ja.com

C ++で名前(std :: string)で関数を呼び出す方法は?

文字列から関数を呼び出す簡単な方法があるのだろうか。 「if」と「else」を使用した簡単な方法を知っています。

int function_1(int i, int j) {
    return i*j;
}

int function_2(int i, int j) {
    return i/j;
}

...
...
...

int function_N(int i, int j) {
    return i+j;
}

int main(int argc, char* argv[]) {
    int i = 4, j = 2;
    string function = "function_2";
    cout << callFunction(i, j, function) << endl;
    return 0;
}

これが基本的なアプローチです

int callFunction(int i, int j, string function) {
    if(function == "function_1") {
        return function_1(i, j);
    } else if(function == "function_2") {
        return function_2(i, j);
    } else if(...) {

    } ...
    ...
    ...
    ...
    return  function_1(i, j);
}

もっと簡単なものはありますか?

/* New Approach */
int callFunction(int i, int j, string function) {
    /* I need something simple */
    return function(i, j);
}
17
Alan Valejo

説明したものはreflectionと呼ばれ、C++ではサポートされていません。ただし、いくつかの回避策があります。たとえば、この非常に具体的なケースでは、関数名(_std::map_オブジェクト)を関数ポインターにマップする_std::string_を使用できます。まったく同じプロトタイプは、見た目よりも簡単です。

_#include <iostream>
#include <map>

int add(int i, int j) { return i+j; }
int sub(int i, int j) { return i-j; }

typedef int (*FnPtr)(int, int);

int main() {
    // initialization:
    std::map<std::string, FnPtr> myMap;
    myMap["add"] = add;
    myMap["sub"] = sub;

    // usage:
    std::string s("add");
    int res = myMap[s](2,3);
    std::cout << res;
}
_

myMap[s](2,3)は、文字列sにマップされた関数ポインターを取得し、この関数を呼び出して_2_および_3_を渡して、この例の出力を_5_

44
LihO

標準関数への標準文字列のマップを使用します。

#include <functional>
#include <map>
#include <string>
#include <iostream>

int add(int x, int y) {return x+y;}
int sub(int x, int y) {return x-y;}

int main()
{
    std::map<std::string, std::function<int(int,int)>>  funcMap =
         {{ "add", add},
          { "sub", sub}
         };

    std::cout << funcMap["add"](2,3) << "\n";
    std::cout << funcMap["sub"](5,2) << "\n";
}

Lambdaでさらに良い:

#include <functional>
#include <map>
#include <string>
#include <iostream>

int main()
{
    std::map<std::string, std::function<int(int,int)>>  funcMap =
         {{ "add", [](int x, int y){return x+y;}},
          { "sub", [](int x, int y){return x-y;}}
         };

    std::cout << funcMap["add"](2,3) << "\n";
    std::cout << funcMap["sub"](5,2) << "\n";
}
21
Martin York

まだ言及されていない別の可能性があります。それはtrueリフレクションです。

このオプションは、名前をアドレスに解決するオペレーティングシステム関数を使用して、実行可能ファイルまたは共有ライブラリからエクスポートされた関数にアクセスすることです。これには、2つの「競技者」dllを「審判」プログラムにロードするなどの興味深い用途があり、実際のコードを互いに戦わせる(リバーシやQuakeをプレイする)ことで、人々がそれをスラグアウトできるようにします。

別のオプションは、コンパイラーによって作成されたデバッグ情報にアクセスすることです。 Windowsでは、すべての作業をシステムDLLまたはMicrosoftからダウンロード可能な無料のDLLにオフロードできるため、互換性のあるコンパイラーにとって驚くほど簡単です。機能の一部は既にWindows APIに含まれています。

ただし、これは言語に関係なくシステムプログラミングのカテゴリに分類されるため、卓越したシステムプログラミング言語である場合にのみC++に関係します。

4
DarthGizka

関数を共有ライブラリに配置することもできます。このようなライブラリをdlopen()で動的にロードし、std :: stringを使用して関数を呼び出すだけです。次に例を示します。

hello.cpp

#include <iostream>

extern "C" void hello() {
    std::cout << "hello" << '\n';
}

main.cpp

#include <iostream>
#include <dlfcn.h>

int main() {
    using std::cout;
    using std::cerr;

    cout << "C++ dlopen demo\n\n";

    // open the library
    cout << "Opening hello.so...\n";
    void* handle = dlopen("./hello.so", RTLD_LAZY);

    if (!handle) {
        cerr << "Cannot open library: " << dlerror() << '\n';
        return 1;
    }

    // load the symbol
    cout << "Loading symbol hello...\n";
    typedef void (*hello_t)();

    // reset errors
    dlerror();

    std::string yourfunc("hello"); // Here is your function

    hello_t hello = (hello_t) dlsym(handle, yourfunc.c_str());
    const char *dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol 'hello': " << dlsym_error <<
            '\n';
        dlclose(handle);
        return 1;
    }

    // use it to do the calculation
    cout << "Calling hello...\n";
    hello();

    // close the library
    cout << "Closing library...\n";
    dlclose(handle);
}

コンパイル:

g++ -fPIC -shared hello.cpp -o hello.so

そして:

g++ main.cpp -o main -ldl

実行:

C++ dlopen demo

Opening hello.so...
Loading symbol hello...
Calling hello...
hello
Closing library...

この例は here から盗まれました。 There dlopen()およびc ++の詳細な説明を参照できます。

4
jav