(前回の続き)
「出力命令」が上手くいく方法
次の手順に従うと「悩ましいカウンタ出力命令」を正常に動作させることができる。
- まずは、「数値を出力に変換する」マクロを(脆弱でも何でもよいので)作る。すなわち、
\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:余談であるが、“整数”を引数にする命令(マクロ)を実装する際にはできるだけ「“整数”であれば何でも受け付ける」ようにするのが望ましいと私は考えている。