如何使用宏参数#1
作为该函数名称的一部分来调用该函数?
它是 的#define
类似物C++
。
代码会向你描述这个简单的想法:
\newsavebox\QAAAX
\newsavebox\QAABX
\savebox\QAAAX{First}
\savebox\QAABX{Second}
\renewcommand{\makak}[1] {
\Q#1X %???? It does not work.
}
\makak{AAA} % i need to call \QAAAX and get the output: First
\makak{AAB} % i need to call \QAABX and get the output: Second
答案1
\documentclass{article}
\begin{document}
\newsavebox\QAAAX
\newsavebox\QAABX
\savebox\QAAAX{First}
\savebox\QAABX{Second}
\newcommand{\makak}[1] {
\usebox{\csname Q#1X\endcsname}%???? It does not work.
}
\makak{AAA} % i need to call \QAAAX and get the output: First
\makak{AAB} % i need to call \QAABX and get the output: Second
\end{document}
答案2
这是 LaTeX3 的方法。新 LaTeX3 内核的某些函数接受控制序列,例如\QAAAX
作为参数(在 中用 表示:N
)\some_kernel_function:N
。大多数(如果不是全部)这些函数都被重载以接受标记序列,然后将其转换为控制序列(对于上述示例,重载将读取\some_kernel_function:c
)。因此,以下两个调用\some_kernel_function:...
完全等效:
\some_kernel_function:N \QAAAX
\some_kernel_function:c { QAAAX }
我选择了 Steven 的 MWE,并用l3coffin
LaTeX3 内核的新模块而不是“普通”盒子来实现它。如果你想知道为什么棺材比盒子好得多,我建议你阅读xcoffins
包。 xcoffins
仅仅是模块的一个前端l3coffin
,专为那些害怕expl3
语法的人设计(我可以理解)。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\coffin_new:N \l_dunaev_AAA_coffin
\coffin_new:N \l_dunaev_AAB_coffin
\hcoffin_set:Nn \l_dunaev_AAA_coffin {First}
\hcoffin_set:Nn \l_dunaev_AAB_coffin {Second}
\NewDocumentCommand \makak { m }
{
\coffin_typeset:cnnnn { l_dunaev_#1_coffin } { l } { T } { 0pt } { 0pt }
}
\ExplSyntaxOff
\begin{document}
\makak{AAA}
\makak{AAB}
\end{document}
我觉得用这个包举个例子可能会更有说明性xcoffins
,因为我上面已经讨论过了,所以就拿这个包来说吧。输出与示例相同expl3
。
\documentclass{article}
\usepackage{xcoffins}
\NewCoffin\QAAAX
\NewCoffin\QAABX
\SetHorizontalCoffin\QAAAX{First}
\SetHorizontalCoffin\QAABX{Second}
\newcommand\makak[1]{%
\expandafter\TypesetCoffin\csname Q#1X\endcsname[l,T]%
}
\begin{document}
\makak{AAA}
\makak{AAB}
\end{document}
对 C++ 声明的评论
在您的问题中,您声称在 C++ 中可以使用 来调用使用宏参数的函数#define
。尽管这是真的,但我强烈劝阻这样做!
让我们考虑这个超级无用的例子:我们想要一个通用的打印函数,它可以打印任何可打印类型的值。因此我们定义
#define PRINT(type, value) print_##type(value)
如果我们现在调用,PRINT(int, i)
这个宏将扩展为print_int(i)
。我们已经遇到了第一个陷阱。如果print_int(int value)
没有实现会怎么样?好吧,我们会收到一条错误消息,可以通过实现相应的函数来纠正。很简单!
不幸的是,当我们使用名称中包含不符合函数名称要求的字符的类型时,这种情况就会失效,例如std::string
。::
函数名称中出现 是非法的,除非在最开始表示其命名空间,即使我们交换宏扩展中的顺序,使宏扩展为std::string_print(…)
而不是print_std::string(…)
我们仍然会得到一个错误(至少对于某些编译器来说),因为根据标准,不允许向std
命名空间添加内容。
所有这些缺点都可以通过以下概念来克服模板在 C++ 中。对于我们愚蠢的通用打印函数,正确的模板应该是这样的
template<typename T>
void print(const T& value) {
std::cout << value << std::endl;
}
就是这样!现在,您可以使用任何重载 的类型来实例化此模板operator<<(std::ostream& out, T& value)
。否则您将收到error: invalid operands to binary expression
。
结论:切勿使用预处理器宏来模仿函数模板!
这是完整的示例,其中包含前文中讨论的一些边缘情况。
#include <iostream>
#include <string>
#include <vector>
// ===
// The macro approach
// ===
#define PRINT(type, value) print_##type(value)
void print_int(int value) {
std::cout << value << std::endl;
}
void print_double(double value) {
std::cout << value << std::endl;
}
/* error! "::" not allow in function name
void print_std::string(std::string value) {
std::cout << value << std::endl;
}
*/
// ===
// The template approach
// ===
template<typename T>
void print(const T& value) {
std::cout << value << std::endl;
}
int main() {
int i = 2;
float f = 3.2;
double d = 5.1;
std::string s("ABC");
PRINT(int, i);
// print_float is not implemented!
// PRINT(float, f); // <- error: use of undeclared identifier 'print_float'
PRINT(double, d);
// PRINT(std::string, s); // <- error: use of undeclared identifier 'print_std'
print(i);
print(f);
print(d);
print(s);
return 0;
}
答案3
有两种可能:\csname #1\endcsname
生成框名称或\csuse{#1}
从etoolbox
。对于这个简单的例子,第一种方法就足够了。
\documentclass{article}
\usepackage{etoolbox}
\newsavebox\QAAAX
\newsavebox\QAABX
\newsavebox\QAACX
\newsavebox\QAADX
\savebox\QAAAX{First}
\savebox\QAABX{Second}
\savebox\QAACX{Third}
\savebox\QAADX{Fourth}
\newcommand{\makak}[1]{%
\usebox{\csname Q#1X\endcsname}%
}
\newcommand{\makakother}[1]{%
\usebox{\csuse{Q#1X}}%
}
\begin{document}
\makak{AAA} % i need to call \QAAAX and get the output: First
\makak{AAB} % i need to call \QAABX and get the output: Second
\makakother{AAC} %
\makakother{AAD} %
\end{document}