Bam*_*ghh 12 c++ python f-string
在 Python 中,可以使用 f-strings 方便地格式化字符串:
a = 42
print(f"a = {a}") # prints "a = 42"
Run Code Online (Sandbox Code Playgroud)
是否可以在编译时在 C++ 中做这样的事情,或者是format("a = {}", a);最接近 f-strings 的东西?
编辑:我并不是说这些格式化方法应该在运行时工作。编译器不能只在编译时通过名称查找当前作用域中可见的变量吗?就像,如果它遇到字符串,f"foo = {foo}"它可以将此字符串替换为std::format("foo = {}", foo)代码
C++ 没有反射。因此,不可能通过名称提供对变量的引用。
但正如@NicolBolas 指出的那样,即使存在反射,也需要更多。它不仅需要大量的语言支持(告诉被调用函数在调用范围内的变量是什么),它还会阻止大量的优化。编译器无法删除任何变量,因为格式字符串(在编译时未知时)最终可能会引用范围内的任何变量。
所以不行。std::format是最接近的。
没有什么好的办法可以做到这一点。
使用一些重宏,您可以实现类似F(a = ARG(a))(whereF和ARGare 宏)的语法,并且它会起作用,但有主要限制(见下文)。
下面是一个依赖 libfmt 的示例实现:
#define F(...) F_LOW( (str, __VA_ARGS__ ) )
#define ARG(...) )(expr, __VA_ARGS__ )(str,
#define F_LOW(...) ::fmt::format(F_END(F_STR_LOOP_A __VA_ARGS__) F_END(F_ARG_LOOP_A __VA_ARGS__))
#define F_END(...) F_END_(__VA_ARGS__)
#define F_END_(...) __VA_ARGS__##_END
#define F_CAT(a, b) F_CAT_(a, b)
#define F_CAT_(a, b) a##b
#define F_STR_LOOP_A(...) F_STR_LOOP_BODY(__VA_ARGS__) F_STR_LOOP_B
#define F_STR_LOOP_B(...) F_STR_LOOP_BODY(__VA_ARGS__) F_STR_LOOP_A
#define F_STR_LOOP_A_END
#define F_STR_LOOP_B_END
#define F_STR_LOOP_BODY(tag, ...) F_CAT(F_STR_LOOP_BODY_, tag)(__VA_ARGS__)
#define F_STR_LOOP_BODY_str(...) #__VA_ARGS__
#define F_STR_LOOP_BODY_expr(...) "{}"
#define F_ARG_LOOP_A(...) F_ARG_LOOP_BODY(__VA_ARGS__) F_ARG_LOOP_B
#define F_ARG_LOOP_B(...) F_ARG_LOOP_BODY(__VA_ARGS__) F_ARG_LOOP_A
#define F_ARG_LOOP_A_END
#define F_ARG_LOOP_B_END
#define F_ARG_LOOP_BODY(tag, ...) F_CAT(F_ARG_LOOP_BODY_, tag)(__VA_ARGS__)
#define F_ARG_LOOP_BODY_str(...)
#define F_ARG_LOOP_BODY_expr(...) , __VA_ARGS__
Run Code Online (Sandbox Code Playgroud)
例如,使用这些宏F(a=ARG(a), b=ARG(b))将相当于 pythonic f"a={a}, b={b}",并将扩展为
::fmt::format("a=" "{}" ", b=" "{}" "", a, b)
Run Code Online (Sandbox Code Playgroud)
这相当于
::fmt::format("a={}, b={}", a, b)
Run Code Online (Sandbox Code Playgroud)
到目前为止看起来不错吗?它甚至可以处理转义序列(以某种方式)!
以下是提到的主要缺点:
任何空白字符序列都将替换为单个空格。
ARG将被删除。字符串中的所有宏都会展开。
该字符串不能包含不平衡的括号。
ARG(...)不能出现在括号内。
IMO,这使得它无法用于除调试输出之外的任何内容。
可能的解决方法包括:
将语法更改为以下之一:
F("a = " ARG(a))(我不喜欢它的样子)F("a = ", (a))(看起来不错,但需要 Boost.Preprocessor 或等效的生成宏)F("a = ", ARG a)(相同的)F("a = ", ()a)(相同的)ARG比方说,添加一个子宏(类似于)STR("...")以逐字包含字符串文字。这将允许您包含任何您想要的空格/括号/未扩展的宏/...。
示例:F(a = ARG(A))给你a =42. 如果您想要后面有一个空格=,就可以F(a = STR(" ") ARG(A))。
语法太晦涩了,所以实现它留给读者作为练习。
...
奖励:使用正确的标志(或#pragmas),大多数编译器将允许您将其包含$在宏名称中。这意味着如果您想的话,您可以使用$(expr)代替...ARG(expr)