(前回の続き)
「出力命令」が上手くいく方法
次の手順に従うと「悩ましいカウンタ出力命令」を正常に動作させることができる。
- まずは、「数値を出力に変換する」マクロを(脆弱でも何でもよいので)作る。すなわち、
\format@hoge{hogeの数値の十進表記}
を実行すると“hoge の出力”が得られるような\format@hoge
を作る。(つまり、\format@hoge{42}
を実行すると“43.”となるべき。) - そのマクロ
\format@hoge
を保護付にする。つまり、\def
(や\newcommand
)の代わりに\DeclareRobustCommand
で定義をする。(あるいは e-TeX 拡張の\protected
を使う。) \thehoge
を以下のように定義する。\def\thehoge{\expandafter\format@hoge\expandafter{\number\c@hoge}}
この手順に従って \thehoge
を実装すると次のようになる。
\DeclareRobustCommand*\format@hoge[1]{% \count@=#1\relax \advance\count@1 \number\count@ .} \def\thehoge{\expandafter\format@hoge\expandafter{\number\c@hoge}}
\protected
を利用する場合のコードも示しておく。
\protected\def\format@hoge#1{% \count@=#1\relax \advance\count@1 \number\count@ .} \def\thehoge{\expandafter\format@hoge\expandafter{\number\c@hoge}}
この実装が先述の「上手くいく条件」を満たしていることを確かめてみよう。ここで、\thehoge
を 2 回展開すると \format@hoge{hogeの数値}
が得られることに注意する。
\thehoge
を実行すると\format@hoge{42}
を経て所望の“43.”が出力されるので OK。\thehoge
の保護付完全展開は\format@hoge{42}
であり、“hoge の数値”の情報が現れているので OK。\format@hoge{42}
を実行すると“43.”が出力され、この時には hoge は参照されていないので OK。
補足
先に示した \format@hoge
の実装では引数の数値を「\count@=#1\relax
」のように参照しているため、引数としては「42
」のような十進数字のみでなく「整数を表す任意のトークン列」を受け付けることができる。*1この場合は \thehoge
の定義は単純に次のようにできる。
\def\thehoge{\format@hoge{\number\c@hoge}}
つまり「先に引数を数字列に展開しておく」必要が無くなるのである。\expandafter
が 2 つも消えて気分爽快である。
アレを作ってみる
最後に、「上手くいく」手順を使って、元々の問題を解決してみよう。
\documentclass[a4paper]{article} \newcounter{piyo} \newcounter{hoge}[piyo] \makeatletter %!!!!!!!!!!!!!!! TeX code BEGIN \DeclareRobustCommand*\format@hoge[2]{% \count@=#1\relax \advance\count@1 \number\count@.\number#2\relax} \def\thehoge{% \format@hoge{\number\c@piyo}{\number\c@hoge}} \makeatother %!!!!!!!!!!!!!!! TeX code END \begin{document} hoge = \ref{test} / \refstepcounter{piyo}% piyo = 1 \refstepcounter{hoge}\label{test}% hoge = 1 hoge = \thehoge \end{document}
(ところでこの実装でも \format@hoge
の実装を工夫している。もし \thehoge
で「引数の 2 つの整数を先に展開するために \expandafter
しないといけない」となるとどんな惨状が待っているかを考えてみてほしい。)
*1:余談であるが、“整数”を引数にする命令(マクロ)を実装する際にはできるだけ「“整数”であれば何でも受け付ける」ようにするのが望ましいと私は考えている。