从TeX 按主题分类,第 111 页:
然而,对于某些应用来说,一些普通宏位于外部会带来不便,特别是如下宏
\newskip
。一种补救措施是重新定义它们,而不使用“外部”选项,例如在 LaTeX 中就是这样做的,但更聪明的技巧也是可能的。
\outer
在通常不允许使用宏的地方使用宏的技巧有哪些例子?
答案1
正如 egreg 所说,标准方式是使用\csname
:只要\outer
定义时没有标记,那么就是安全的。
因此,另一种可能性是,在一个组中,使宏非外部,定义你的宏,然后重置所有内容:
\begingroup
\let\newdimen\relax
\gdef\makedimenandgivevalue#1#2{%
\newdimen#1%
#1=#2\relax}
\endgroup
此版本的问题在于,如果您需要将\outer
宏作为参数传递给辅助函数,则无法做到这一点。更方便的版本是为宏定义一个非外部包装器\outer
,然后您就可以自由使用它:
\edef\mynewdimen{\noexpand\newdimen}
%
\def\makedimenandgivevalue#1#2{%
\mynewdimen#1%
#1=#2\relax
}
答案2
答案3
著名的\cleartabs
、\settabs
和\+
宏plain.tex
展示了这样一个技巧(TeXbook 第 354 页):
\let\+=\relax % in case this file (plain.tex) is being read in twice
\def\sett@b{\ifx\next\+ \let\next=\relax % turn off \outerness
\def\next{\afterassignment\s@tt@b\let\next}%
\else\let\next=\s@tcols\fi\next}
...
\outer\def\+{\tabalign}
\let\+=\relax
在定义之前完成,\sett@b
以防\+
已经是一个\outer
标记(否则,\+
的替换文本中的标记在定义\sett@b
时会导致错误)。\sett@b
当文档中 的
\ifx\next\+
正常使用过程中测试为真时,是一个标记,因为 在正常使用中,是。因此,Knuth在用重新定义之前会这样做,否则此定义中替换文本末尾的标记将导致错误。\settabs
\next
\outer
\+
\outer
\let\next=\relax
\next
\def\next{\afterassignment\s@tt@b\let\next}
\next
答案4
如果 \outer
-tokens 被 击中\noexpand
,它们将被变成\relax
(仅)用于下一次扩展:
\documentclass{article}
\outer\def\myoutermacro{My outer macro's definition.}
\def\FirstOfOne#1{#1}%
\newtoks\myscratchtoks
\begin{document}
% This does not work:
%
% \FirstOfOne{\myoutermacro}.
%
% These do work:
\expandafter\FirstOfOne\expandafter{\noexpand\myoutermacro}
\myscratchtoks\expandafter{\noexpand\myoutermacro}
\FirstOfOne{\the\myscratchtoks}
\edef\myscratchmacro{\noexpand\myoutermacro}
\FirstOfOne{\myscratchmacro}
\end{document}