【发布时间】:2017-03-26 17:54:45
【问题描述】:
我想创建std::fscanf() 的一些兄弟姐妹(我知道它是一个 C 函数)。所以,我的界面是这样的:
template <charT, char_traits, ...>
std::size_t ts_scanf(is, format, opening_bracket, closing_bracket, args)
我决定实现从控制台读取的 C# 版本,因为它要求程序员只维护一个序列(args 部分),而不是参数和格式。
C# 版本的工作原理如下:
"text blah blah blah {0} {1} {0}", arg1, arg2
因此,它推断出 arg1、arg2 的类型,然后将 {N} 所在位置的文本读取到适当的参数中。
算法我想做什么:
1.查找左括号
2.尝试解析一个int,比如N
3.如果成功,从包中获取第N个参数,使用is>>get<N>args读入。
4.如果失败,执行哑读
5.重复 1 到 4 直到格式结束或直到流耗尽
所以,在写循环的时候我遇到了一个问题:
for (i = 0; i < length; i = format.find(i, opening_bracket))
我发现我需要以某种方式扩展参数包args,这在运行时是不可能做到的(因为循环是运行时的)。我想到的唯一解决方案是递归:找到左括号时,读取它,修剪格式字符串,然后使用修剪后的字符串和可变参数包的其余部分进行递归。
问题:是否有一种解决方案可以在(伪)运行时扩展可变参数包?
【问题讨论】:
-
opening_bracket和closing_bracket是什么?你为什么需要那个?fscanf没有类似的 AFAIK。一个关于你希望它如何工作的伪代码在解释方面比用文字表达要大得多。 -
@Arunmu,谢谢,已添加
-
如果你想真正高效地完成它,那么你应该使用表达式模板在编译时完成它(映射)。这可以使用
boost::proto来完成,尽管我承认它不适合弱者:)。我知道的另一个解决方案只是纯粹的运行时,因为您将只在运行时解析括号。这将涉及将参数存储在运行时容器中。 -
@Arunmu,我相信我只会考虑 {},而不是 {N},因为它需要魔法才能发生。否则我可以把函数扔到对象上,因为我不能把对象扔到函数上。
-
github.com/fmtlib/fmt 已经按照我的理解做了你想做的事情。
标签: c++ input variadic-templates