
コマンドにスター付きバージョンを追加するメタマクロをどのように記述すればよいでしょうか?
想定される使用法は次の通りです
\newcommand\foo[1]{foo is #1}
\addstarred\foo[2]{foo is #1, bar is #2}
答え1
David Kastrup によるパッケージではすでにメソッドが利用可能ですsuffix
。言うまでもなく、巧妙なトリックが満載です。
こう言うこともできる
\usepackage{suffix}
\newcommand{\foo}[1]{foo is #1}
\WithSuffix\newcommand\foo*[2]{foo is #1, bar is #2}
そして、その目的がどのように達成されるかを見ることは有益かもしれません。
\show\foo
2番目の命令の後に実行すると、
> \foo=\protected macro:
->\WSF@suffixcheck \foo .
suffix
そこで、 はe-TeX(最近は問題にならない)を必要とし、\foo
を意味するように再定義することがわかります\WSF@suffixcheck\foo
。そこで を追加し\makeatletter
て試す\show\WSF@suffixcheck
と、
> \WSF@suffixcheck=macro:
#1->\begingroup \def \reserved@a {#1}\futurelet \reserved@b \WSF@suffixcheckii
引数は保存され\reserved@a
、
\futurelet\reserved@b\WSF@suffixcheckii
が実行されます。これにより、\reserved@b
は に続くトークンと同等になります\WSF@suffixcheckii
。呼び出しが
\foo{foo}
と\reserved@b
なるでしょう\bgroup
。呼び出しが
\foo*{foo}{bar}
と\reserved@b
なるでしょう*
。ここで、以下が何を意味するのかを知る必要があります\WSF@suffixcheckii
。
> \WSF@suffixcheckii=macro:
->\ifcsname \expandafter \SuffixName \reserved@a \reserved@b \endcsname
\expandafter \WSF@suffixcheckiii \else \expandafter \WSF@suffixcheckiv \fi .
さて、 の場合に何が起こるか見てみましょう\foo{foo}
。\reserved@a
は に展開されます\foo
が、\reserved@b
は\bgroup
(展開不可能)なので、TeXは最初に次のように表示されます。
\ifcsname\SuffixName\foo\reserved@b\endcsname
そして\SuffixName
次のように定義される。
> \SuffixName=\long macro:
#1->WSF:\string #1 \meaning .
次のステップは
\ifcsname WSF:\string\foo \meaning\reserved@b\endcsname
そしてついに
\ifcsname WSF:\foo begin-group character {\endcsname
ここで、すべての文字のカテゴリコードは12です(ただし、スペースは10です)。この\foo*{foo}{bar}
場合、
\ifcsname WSF:\foo the character *\endcsname
コマンド\csname WSF:\foo begin-group character {\endcsname
が定義されていないため、偽のブランチが実行されます。
\expandafter \WSF@suffixcheckiv \fi
それは単に
\WSF@suffixcheckiv{foo}
入力ストリームに次のもの\show\WSF@suffixcheckiv
を追加します。
> \WSF@suffixcheckiv=macro:
->\expandafter \endgroup \csname \expandafter \NoSuffixName \reserved@a \endcsname .
以前開いたグループは閉じられますが、まず
\csname \expandafter \NoSuffixName \reserved@a \endcsname
が形成される。 は\reserved@a
に展開される\foo
ので、
\csname \NoSuffixName \foo \endcsname
そして\NoSuffixName
> \NoSuffixName=macro:
->WSF:\string .
最終的に得られるのは
\csname WSF:\string\foo\encsname
さて、発行しましょう\expandafter\show\csname WSF:\string\foo\endcsname
:
> \WSF:\foo=\long macro:
#1->foo is #1.
つまり、この複雑なマクロは元のマクロのコピーです\foo
。
\foo*{foo}{bar}
我々の場合、
\ifcsname WSF:\foo the character *\endcsname
しかし、この場合はは定義済み; 確かに
\expandafter\show\csname WSF:\string\foo\space the character *\endcsname
生産する
> \WSF:\foo the character *=\long macro:
#1#2->foo is #1, bar is #2.
したがって、複雑な名前を持つこのマクロは、*
-variant として定義されたものです。
このパッケージでは、ほぼすべてのトークンを接尾辞として使用できます。しかし、基本的な考え方はあなたが考案したものと変わりません。既存のマクロ名を上書きすることに対する保護がより優れています。パッケージが行うことは、
\WithSuffix\newcommand\foo*[2]{foo is #1, bar is #2}
処理される
元の
\foo
コマンドを以下に保存します\csname WSF:\string\foo\endcsname
\WithSuffix
(このステップに先行して適用されたものがすでに存在する場合は、\foo
当然省略されます)新しい定義を以下に保存します
\csname WSF:\string\foo\space the character *\endcsname
さまざまなサフィックスを選択するには、上記の抽象インターフェースを使用します。
答え2
以下に、@egreg と @DavidCarlisle が親切にも提供してくれた改善を加えた、私自身の解決策の試みを示します。
\documentclass{standalone}
\makeatletter
\newcommand\addstarred[1]{%
\expandafter\let\csname\string#1@nostar\endcsname#1%
\edef#1{\noexpand\@ifstar\expandafter\noexpand\csname\string#1@star\endcsname\expandafter\noexpand\csname\string#1@nostar\endcsname}%
\expandafter\newcommand\csname\string#1@star\endcsname%
}
\makeatother
\newcommand\foo[1]{foo is #1}
\addstarred\foo[2]{foo is #1, bar is #2}
\begin{document}
\foo{red} --- \foo*{red}{green}
\end{document}
結果:
説明:
- コマンドの現在の定義のコピーは
\foo
として保存されます\\foo@nostar
。 - コマンドは、
\foo
星印をチェックし、 または を呼び出すように再定義されます\\foo@star
。\\foo@nostar
これは、edef
構築されたトークン名を、コマンドが呼び出されるたびにではなく、その場で展開できるようにするために行われます。 - for
\newcommand
が\\foo@star
開始され、定義の残りは次のように実行されます\addstarred\foo
。