6

実行時に関数呼び出しの引数リストを生成しようとしていますが、これを C++ で実現する方法が思いつきません。

これは、私が書いているヘルパー ライブラリ用です。ネットワーク経由でクライアントから入力データを取得し、そのデータを使用して、ユーザーが以前に設定した関数ポインターを呼び出しています。この関数は文字列 (printf に似たトークンの) と、さまざまな量の引数を取ります。私が必要としているのは、クライアントから受け取ったデータに応じて引数を追加する方法です。

関数ポインターのマップに関数を格納しています

typedef void (*varying_args_fp)(string,...);
map<string,varying_args_fp> func_map;

使用例は次のとおりです。

void printall(string tokens, ...)
{
    va_list a_list;
    va_start(a_list, tokens);

    for each(auto x in tokens)
    {
        if (x == 'i')
        {
            cout << "Int: " << va_arg(a_list, int) << ' ';
        }
        else if(x == 'c')
        {
            cout << "Char: " << va_arg(a_list, char) << ' ';
        }
    }

    va_end(a_list);
}

func_map["printall"] = printall;
func_map["printall"]("iic",5,10,'x');
// prints "Int: 5 Int: 10 Char: x"

これは、関数呼び出しとその引数をハードコーディングするときにうまく機能しますが、データ「CreateX 10 20」を受け取った場合、プログラムは引数呼び出し自体を行うことができる必要があります。例えば

// func_name = "CreateX", tokens = 'ii', first_arg = 10, second_arg = 20
func_map[func_name](tokens,first_arg,second_arg);

ユーザーが関数をどのようにレイアウトし、これをコーディングするかを事前に予測することはできません。

このタスクを別の方法で達成するための提案がある場合は、遠慮なく提案してください。ユーザーが関数をライブラリに「バインド」できるようにする必要があり、ライブラリがネットワーク化されたクライアントからデータを受信した後にそれを呼び出すには、本質的にコールバックが必要です。

4

2 に答える 2

2

@TonyTheLion で既に述べたように、実行時にboost::variantまたはを使用boost::anyしてタイプを選択できます。

typedef std::function<void(const std::string&, const std::vector<boost::variant<char, int>>&)> varying_args_fn;
std::map<std::string, varying_args_fn> func_map;

たとえば、静的ビジターを使用してタイプを区別できます。以下に完全な例を示します。実行時にどのタイプが格納されているかを認識しているため、このtokensパラメーターは実際には不要であることに注意してください。boost::variant

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

#include <boost/variant.hpp>
#include <boost/any.hpp>

typedef std::function<void(const std::string&, const std::vector<boost::variant<char, int>>&)> varying_args_fn;

void printall(const std::string& tokens, const std::vector<boost::variant<char, int>>& args) {
  for (const auto& x : args) {
    struct : boost::static_visitor<> {
      void operator()(int i) {
        std::cout << "Int: " << i << ' ';
      }
      void operator()(char c) {
        std::cout << "Char: " << c << ' ';
      }
    } visitor;
    boost::apply_visitor(visitor, x);
  }
}

int main() {
  std::map<std::string, varying_args_fn> func_map;
  func_map["printall"] = printall;
  func_map["printall"]("iic", {5, 10, 'x'});
}
于 2013-04-02T14:09:37.763 に答える