我有一个函数unpack
,它应该从一个可变参数模板表达式构造一个std::tuple
。该函数看起来像这样(包括注解失败的表达式):
template<typename T, typename... Ts>
std::tuple<T,Ts...> unpack(std::stringstream& ss)
{
T t{};
WriteTypeStruct ret{};
if (writeType(ret, ss, t); (!ss || ret.err)) {
throw std::runtime_error(ret.msg);
}
//std::tuple args = {extract<std::decay_t<Ts>>(ss)...};
//std::tuple args = unpack<typename std::decay_t<Ts>...>(ss);
//return {t, unpack<Ts>(ss)...};
//return std::make_tuple(t, unpack<Ts>(ss)...);
//std::tuple<Ts...> unpacked = {unpack<Ts>(ss)...};
//return std::make_tuple(t, unpacked);
//return std::tuple_cat(std::tuple<T>(t), std::make_from_tuple(unpack<Ts>(ss)...));
return std::make_tuple(t, std::make_from_tuple<Ts...>(unpack<Ts>(ss)...)); // <-- cannot compile!
}
字符串
函数writeType
是一系列模板化的重载函数,我用它来检查是否可以从std::stringstream
中提取预期的类型。这个函数在WriteTypeStruct
中放置一些返回值,其中包含一个布尔值和一个错误消息字符串。
我正在为命令控制台写一个基于字符串的解释器。
这里给出了这个问题的完整演示:如何为基于文本的命令控制台存储参数化的强类型函数,特别是@jarod42的答案。我使用这个unpack
函数而不是extract
。
关于如何扁平化std::tuple
here,有一个很好的解释,但我希望通过首先不创建嵌套元组来避免这种代码。
但我好像不知道正确的语法。
1条答案
按热度按时间nbysray51#
我会先从alteralize开始:
字符串
这个语义很简单
型
这些
{}
中的求值顺序是有保证的。(注意:这是因为我使用了{}
ctor,而不是函数调用。程序员可以很容易地对上面的内容进行修改,“什么都不做”,并以一种可怕的方式破坏它,这取决于你使用的编译器。)大多数
unpack
尝试的一个问题是它们不能很好地处理unpack<>
(终止情况)。调用
unpack<Ts>...
而不是unpack<Ts...>
(即,保证传递1,并且在0处消除unpack调用)的那些最终会导致元组的层数过多,unpack<Ts>...
是一组元组,您可以将其 Package 在元组中。型
就差一点了。要解决这个问题:
型
只需删除
unpack
s上tuple
额外层;unpack
已经返回了一个元组。然后我们将返回tuple_cat
,它支持任意数量的元组。我们可以尝试优化它:
型
但这会遇到空
unpack<>
问题。我在这里遇到的一个问题是,你把所有东西都放进一个元组中,只是为了再次把它取出来。
空的
unpack<>
也可以处理。在您的unpack
之前添加:型
那么
unpack<>
应该调用这个重载。然而,我发现所有这些都不如从元组版本调用的1元素版本优雅。
最后,我们可以写一个tuple flatten函数,它接受任何一组参数,如果其中任何一个是元组,它就将它们替换,并返回融合列表。我个人认为这个函数很有吸引力,但这是一个坏主意,因为它立即“解决”了一个问题,并在以后导致棘手的问题。
这有点像写一个函数,它不转义文本,但不转义任何层,直到没有更多的转义序列。或者一个转义文本,但拒绝转义任何已经转义的东西。
你把它扔到一个业务逻辑链中,它“解决”了一个不均匀转义或未转义数据的问题......并以无法修复的方式破坏了事物。