[英]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 );
}
應該這樣做。 可能包含錯別字。 c ++ 17 。
boost
具有等效的類型( variant
和optional
),可以通過一些調整來替換上面的std
用法。
fold pack擴展可以用c ++ 11或更高版本中的expand-in-array hack代替。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.