对 C++ 声明的评论

对 C++ 声明的评论

如何使用宏参数#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,并用l3coffinLaTeX3 内核的新模块而不是“普通”盒子来实现它。如果你想知道为什么棺材比盒子好得多,我建议你阅读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}

在此处输入图片描述

相关内容