C 预处理器字符串化(再次)
C Preprocessor stringification (again)
stringification
在数值评估后是否可以
?
用一个简单的例子可以更好地解释这一点:
#define A 1
#define B 2
#define SUM (A + B)
#define STR_IMPL_(x) #x
#define STR(x) STR_IMPL_(x)
char *sum = STR(SUM);
正如所写,这会生成单行:
char *sum = "(1 + 2)";
是否有可能以某种方式生成 char *sum = "3";
?
我怀疑这是不可能的,因为 CPP 是一个纯文本处理器(尽管它 可以 做算术运算,至少在条件语句中是这样),但我可能忽略了一些东西。
#include <boost/preprocessor/arithmetic/add.hpp>
char* sum = STR(BOOST_PP_ADD(A,B));
Is it possible to have stringification after numeric evaluation?
是的。作为参考,这里有一些我将使用的具体定义:
- 算术使用加、减、乘、除等常用原语对数字进行计算的能力
- 表达式使用括号分组、中缀运算符+、-、*、/等常用运算符的算术语法表示
算术方法
鉴于这些定义,宏展开不能计算表达式,但它们可以执行算术运算。您可以使用宏代替运算符,每个宏都会从头开始实现算术。这是使用这种方法的 boost pp 用法:
#include <boost/preprocessor/arithmetic.hpp>
#include <boost/preprocessor/stringize.hpp>
#define A 1
#define B 2
#define SUM BOOST_PP_ADD(A, B)
BOOST_PP_STRINGIZE(SUM)
使用这种方法,您只需将宏扩展为结果即可;然后可以将该结果字符串化。但是你是在宏中实现算术本身而不是运算符,这需要很多宏。因此,要做到这一点,要么 您的数字范围需要严格限制,或 您需要使用可分解为宏观评估的数字(例如, 将 20000 表示为 (2,0,0,0,0)
而不是 20000
)。 Boost pp 算法使用前一种方法(适用于从 0
到 256
的范围;是的,我知道那是 257 个数字)。
表达方式
或者,您可以计算表达式。如前所述,预处理器可以评估条件指令中的表达式。将其用作原语,您可以梳理出结果;例如,如果 EXPRESSION
扩展为您的表达式,您可以 #define D0
,表示结果的单位数字,使用如下结构:
#if ((EXPRESSION)%10)==9
#define D0 9
#elif ((EXPRESSION)%10)==8
#define D0 8
...
然后你可以类似地 #define
D1
是十位的特定数字,D2
是百位,等等......然后有一个 RESULT
宏展开为 ... D3##D2##D1##D0
。将整个东西包装成 evaluator.hpp
之类的东西,你可以通过将 EXPRESSION
定义为你的表达式,使用 #include "evaluator.hpp"
来计算它,最后使用 RESULT
来输入任意表达式表示结果。使用这种方法,每个 "evaluator" 都需要为特定数字定义的特定 Dx 宏才能工作...因此其行为类似于 "variables",但会消耗整个计算器。
Boost pp 具有此功能,每个评估器称为 "slot",并提供 5 个插槽。所以你必须用 #include
抽水,每个评估者一次只能存储一个结果......但在 return 中你的范围是 not 限制(超过本机范围)并且您实际上是在评估表达式。这是使用 boost pp 使用此方法的示例:
#include <boost/preprocessor/slot/slot.hpp>
#include <boost/preprocessor/stringize.hpp>
#define A 1
#define B 2
#define SUM (A+B)
#define BOOST_PP_VALUE SUM
#include BOOST_PP_ASSIGN_SLOT(1)
BOOST_PP_STRINGIZE(BOOST_PP_SLOT(1))
(编辑:手动计算器 here (wandbox) 可能值得回顾一下,看看上面解释的机制是如何工作的)。
TL;DR 摘要
算术
- pro: 完全通过宏调用求值
- con: 宏而不是中缀运算符
- con:范围有限或使用替代文字表示
表达式
- pro:评估实际表达式(中缀、组等)
- pro: ranges as open as native ranges, with 普通文字
- con: 需要 `#include` 来抽取通用机制
- con:重用求值器必须丢失之前的结果
stringification
在数值评估后是否可以
用一个简单的例子可以更好地解释这一点:
#define A 1
#define B 2
#define SUM (A + B)
#define STR_IMPL_(x) #x
#define STR(x) STR_IMPL_(x)
char *sum = STR(SUM);
正如所写,这会生成单行:
char *sum = "(1 + 2)";
是否有可能以某种方式生成 char *sum = "3";
?
我怀疑这是不可能的,因为 CPP 是一个纯文本处理器(尽管它 可以 做算术运算,至少在条件语句中是这样),但我可能忽略了一些东西。
#include <boost/preprocessor/arithmetic/add.hpp>
char* sum = STR(BOOST_PP_ADD(A,B));
Is it possible to have stringification after numeric evaluation?
是的。作为参考,这里有一些我将使用的具体定义:
- 算术使用加、减、乘、除等常用原语对数字进行计算的能力
- 表达式使用括号分组、中缀运算符+、-、*、/等常用运算符的算术语法表示
算术方法
鉴于这些定义,宏展开不能计算表达式,但它们可以执行算术运算。您可以使用宏代替运算符,每个宏都会从头开始实现算术。这是使用这种方法的 boost pp 用法:
#include <boost/preprocessor/arithmetic.hpp>
#include <boost/preprocessor/stringize.hpp>
#define A 1
#define B 2
#define SUM BOOST_PP_ADD(A, B)
BOOST_PP_STRINGIZE(SUM)
使用这种方法,您只需将宏扩展为结果即可;然后可以将该结果字符串化。但是你是在宏中实现算术本身而不是运算符,这需要很多宏。因此,要做到这一点,要么 您的数字范围需要严格限制,或 您需要使用可分解为宏观评估的数字(例如, 将 20000 表示为 (2,0,0,0,0)
而不是 20000
)。 Boost pp 算法使用前一种方法(适用于从 0
到 256
的范围;是的,我知道那是 257 个数字)。
表达方式
或者,您可以计算表达式。如前所述,预处理器可以评估条件指令中的表达式。将其用作原语,您可以梳理出结果;例如,如果 EXPRESSION
扩展为您的表达式,您可以 #define D0
,表示结果的单位数字,使用如下结构:
#if ((EXPRESSION)%10)==9
#define D0 9
#elif ((EXPRESSION)%10)==8
#define D0 8
...
然后你可以类似地 #define
D1
是十位的特定数字,D2
是百位,等等......然后有一个 RESULT
宏展开为 ... D3##D2##D1##D0
。将整个东西包装成 evaluator.hpp
之类的东西,你可以通过将 EXPRESSION
定义为你的表达式,使用 #include "evaluator.hpp"
来计算它,最后使用 RESULT
来输入任意表达式表示结果。使用这种方法,每个 "evaluator" 都需要为特定数字定义的特定 Dx 宏才能工作...因此其行为类似于 "variables",但会消耗整个计算器。
Boost pp 具有此功能,每个评估器称为 "slot",并提供 5 个插槽。所以你必须用 #include
抽水,每个评估者一次只能存储一个结果......但在 return 中你的范围是 not 限制(超过本机范围)并且您实际上是在评估表达式。这是使用 boost pp 使用此方法的示例:
#include <boost/preprocessor/slot/slot.hpp>
#include <boost/preprocessor/stringize.hpp>
#define A 1
#define B 2
#define SUM (A+B)
#define BOOST_PP_VALUE SUM
#include BOOST_PP_ASSIGN_SLOT(1)
BOOST_PP_STRINGIZE(BOOST_PP_SLOT(1))
(编辑:手动计算器 here (wandbox) 可能值得回顾一下,看看上面解释的机制是如何工作的)。
TL;DR 摘要
- 算术
- pro: 完全通过宏调用求值
- con: 宏而不是中缀运算符
- con:范围有限或使用替代文字表示
- 表达式
- pro:评估实际表达式(中缀、组等)
- pro: ranges as open as native ranges, with 普通文字
- con: 需要 `#include` 来抽取通用机制
- con:重用求值器必须丢失之前的结果