[英]How to pass a variable number and type of arguments to template function?
I'm setting up a console command that takes a variable number of arguments, each of which can be basic types (int, float, bool, string) and then pass them to a function that has 8 overloads for supporting a different number of arguments of varying types. 我正在设置一个控制台命令,该命令接受可变数量的参数,每个参数可以是基本类型(int,float,bool,string),然后将它们传递给具有8个重载的函数,以支持不同数量的参数不同的类型。 How would I parse the command line string into values based on their type and then pass them to the function? 如何将命令行字符串根据其类型解析为值,然后将其传递给函数?
I can retrieve each argument via the function const char* GetArg(int index)
. 我可以通过函数const char* GetArg(int index)
检索每个参数。 Converting the char*
to the proper type isn't an issue so don't worry about that part. 将char*
转换为正确的类型不是问题,因此不必担心该部分。 Storing the values and somehow passing to the template function is the part I'm stuck on. 存储值并以某种方式传递给模板功能是我要坚持的部分。
For example, if the command was executed with the following string: "command 66 true 5 "string value" 0.56" 例如,如果命令使用以下字符串执行:“命令66 true 5”字符串值“ 0.56”
It would then be broken up into the following args and stored somehow: 然后将其分解为以下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
And then based on the number of args, call the correct template function: 然后根据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;
}
How would you make this possible? 您将如何做到这一点? Storing the args in some way that can be passed to the template function so that it knows the type of each argument doesn't seem possible, but I feel like I'm just not thinking of something. 以某种可以传递给模板函数的方式存储args,以便它似乎无法知道每个参数的类型,但是我觉得我只是在想什么。
I can't change this interface either. 我也不能更改此界面。 This is a third party function that I just have to deal with. 这是我只需要处理的第三方功能。 So no matter how it is implemented, eventually it has to go through SomeFunc()
. 因此,无论如何实现,最终都必须通过SomeFunc()
。
IMPORTANT: I'm doing this in Visual Studio 2012 so I'm rather limited on newer C++ features. 重要说明:我正在Visual Studio 2012中执行此操作,因此我相当受限于新的C ++功能。 It can do a little bit of C++11 but that's it. 它可以做一点C ++ 11,仅此而已。 Trying to upgrade the project to a newer version but for now that's what I have to deal with. 尝试将项目升级到新版本,但是现在这是我必须处理的。
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 );
}
that should do it. 应该这样做。 Probably contains typos. 可能包含错别字。 c++17 . c ++ 17 。
boost
has equivalent types ( variant
and optional
) that could replace the std
use above, with some tweaks. boost
具有等效的类型( variant
和optional
),可以通过一些调整来替换上面的std
用法。
The fold pack expansion can be replaced with the expand-in-array hack in c++11 or greater. fold pack扩展可以用c ++ 11或更高版本中的expand-in-array hack代替。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.