我正在设置一个控制台命令,该命令接受可变数量的参数,每个参数可以是基本类型(int,float,bool,string),然后将它们传递给具有8个重载的函数,以支持不同的不同类型的参数数量。如何根据类型将命令行字符串解析为值,然后将它们传递给函数?
我可以通过函数const char* GetArg(int index)
检索每个参数。将char*
转换为正确的类型不是问题所以不要担心该部分。存储值并以某种方式传递给模板函数是我坚持的部分。
例如,如果使用以下字符串执行命令:“command 66 true 5”string value“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,但就是这样。试图将项目升级到更新版本,但现在我必须处理这个问题。
答案 0 :(得分:1)
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
),并进行了一些调整。
可以使用c++11或更高版本中的扩展阵列黑客替换折叠包扩展。