использование \def в \newcommand

использование \def в \newcommand

Рассмотрим такой пример:

\documentclass{report}
\def\startnewpart{FALSE}
\makeatletter
\renewcommand\chapter{\if@openright\cleardoublepage\else\clearpage\fi                                                                                                                                       
%                    \def\startnewpart{FALSE} 
                    \thispagestyle{plain}%                                                                                                                                                                  
                    \global\@topnum\z@
                    \@afterindentfalse
                    \secdef\@chapter\@schapter
%                    \def\startnewpart{FALSE}                                                                                                                                                               
}
\makeatother
\begin{document}
\tableofcontents
\chapter{Methods}
Some text
\end{document}

Если \renewcommand\chapterя раскомментирую первый, \def\startnewpart{FALSE}документ скомпилируется нормально.

Если вместо этого я раскомментирую второй, то \def\startnewpart{FALSE}получу ошибку:

Chapter 1.
! Missing { inserted.
\@makechapterhead ...1\par \nobreak \vskip 40\p@ }

l.21 \tableofcontents

В чем разница?

В этом примере я изучаю, как использовать управляющую переменную \startnewpartдля управления выполнением \chapter. \def\startnewpart{FALSE}Она предназначена для сброса значения \startnewpart.

решение1

\secdefопределяется как

% latex.ltx, line 6086:
\def\secdef#1#2{\@ifstar{#2}{\@dblarg{#1}}}

В вашем случае вы получаете

\@ifstar{\@schapter}{\@dblarg{\@chapter}}

Теперь \@ifstarсмотрим на следующий токен. Если раскомментировать вторую \defстроку, то следующим токеном будет не *, а \def. Таким образом, LaTeX находит

\@dblarg{\@chapter}\def\startnewpart{FALSE}

Вот определение \@dblarg:

% latex.ltx, line 1105:
\long\def\@dblarg#1{\kernel@ifnextchar[{#1}{\@xdblarg{#1}}}

Таким образом вы получаете

\kernel@ifnextchar[{\@chapter}{\@xdblarg{\@chapter}}\def\startnewpart{FALSE}

Макрос \kernel@ifnextcharпоглощает три аргумента, здесь [, {\@chapter}и {\@xdblarg{\@chapter}}и проверяет, является ли следующий токен [. Это не так, потому что это \def, поэтому эффект заключается в том, чтобы получить

\@xdblarg{\@chapter}\def\startnewpart{FALSE}

Хорошо, давайте посмотрим \@xdblarg:

% latex.ltx, line 1106:
\long\def\@xdblarg#1#2{#1[{#2}]{#2}}

Вот (но по правилам скобки будут удалены), так что в итоге у вас #1получится{\@chapter}

\@chapter[{\def}]{\def}\startnewpart{FALSE}

что, безусловно, не то, что вы хотели бы иметь в своем коде.

На самом деле это не связано с \def. Такие команды, как

\secdef\A\B
\@ifstar{A}{B}
\@ifnextchar<char>{A}{B}

долженвсегдаидут последними в коде определения, потому что хотят увидеть, что будет дальше.

Связанный контент