簡體   English   中英

如何將可變數量和參數類型傳遞給模板函數?

[英]How to pass a variable number and type of arguments to template function?

我正在設置一個控制台命令,該命令接受可變數量的參數,每個參數可以是基本類型(int,float,bool,string),然后將它們傳遞給具有8個重載的函數,以支持不同數量的參數不同的類型。 如何將命令行字符串根據其類型解析為值,然后將其傳遞給函數?

我可以通過函數const char* GetArg(int index)檢索每個參數。 char*轉換為正確的類型不是問題,因此不必擔心該部分。 存儲值並以某種方式傳遞給模板功能是我要堅持的部分。

例如,如果命令使用以下字符串執行:“命令66 true 5”字符串值“ 0.56”

然后將其分解為以下args並以某種方式存儲:

int arg1 = GetArg(1); // 66
bool arg2 = GetArg(2); // true
int arg3 = GetArg(3); // 5
char* arg4 = GetArg(4); // "string value"
float arg5 = GetArg(5); // 0.56

然后根據args的數量,調用正確的模板函數:

// The function definition looks something like this:
void SomeFunc();
template<typename T1>
void SomeFunc(const T1& arg1);
template<typename T1, typename T2>
void SomeFunc(const T1& arg1, const T2& arg2);
// etc...

// And then somehow it would be called. This is just an example. I don't
// know how to call it in a way that would work with variable number and
// type of args.
switch (argCount)
{
case 0:
    SomeFunc();
    break;
case 1:
    SomeFunc(arg1);
    break;
case 2:
    SomeFunc(arg1, arg2);
    break;
case 3:
    SomeFunc(arg1, arg2, arg3);
    break;
case 4:
    SomeFunc(arg1, arg2, arg3, arg4);
    break;
case 5:
    SomeFunc(arg1, arg2, arg3, arg4, arg5);
    break;
}

您將如何做到這一點? 以某種可以傳遞給模板函數的方式存儲args,以便它似乎無法知道每個參數的類型,但是我覺得我只是在想什么。

我也不能更改此界面。 這是我只需要處理的第三方功能。 因此,無論如何實現,最終都必須通過SomeFunc()

重要說明:我正在Visual Studio 2012中執行此操作,因此我相當受限於新的C ++功能。 它可以做一點C ++ 11,僅此而已。 嘗試將項目升級到新版本,但是現在這是我必須處理的。

using basic_type = std::variant<int, float, bool, std::string>;

using flat_arguments = std::vector<basic_type>;

template<std::size_t...Ns>
using packed_arguments = std::variant< std::array<basic_type, Ns>... >;

template<class T, std::size_t...Ns>
std::array<T, sizeof...(Ns)> pack_one( std::vector<T> n, std::index_sequence<Ns...> ) {
  return {{ std::move(n[Ns])... }};
}

template<class T, std::size_t...Ns>
std::optional<std::variant< std::array<T, Ns>... >>
pack_all(std::vector<T> n, std::index_sequence<Ns...> ) {
  std::optional<std::variant< std::array<T, Ns>... >> retval;
  if (n.size() >= sizeof...(Ns)) { return retval; }
  (
    (
      (n.size()==Ns)?
        void(retval.emplace( pack_one( std::move(n), std::make_index_sequence<Ns>{} ):
        void()
    ),...
  );
  return retval;
}

flat_arguments get_arguments( int argc, char const* const*argv); // write this

auto invoke_somefunc = [](auto&&...args){
  return SomeFunc( decltype(args)(args)... );
};

int main(int argc, char const*const* argv) {
  auto args = get_arguments(argc, argv);
  auto args_packed = pack_all(std::move(args), std::make_index_sequence<9>{} );
  if (!args_packed) return -1;
  std::visit( [](auto&& args){
    std::apply( [](auto&&...args){
      std::visit( invoke_somefunc, args... );
    }, args );
  }, args_packed );
}

應該這樣做。 可能包含錯別字。

boost具有等效的類型( variantoptional ),可以通過一些調整來替換上面的std用法。

fold pack擴展可以用或更高版本中的expand-in-array hack代替。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM