\apptocmd em uma condicional — por que não funciona?

\apptocmd em uma condicional — por que não funciona?

Por que o seguinte MWE não funciona enquanto se eu comentar a condicional ele funciona?

\documentclass{beamer}

\makeatletter

\@ifclassloaded{beamer}{

\usepackage{bookmark}
\usepackage{etoolbox}

\apptocmd{\beamer@@frametitle}{\only<1>{\bookmark[page=\the\c@page,level=3]{#1}}}%
{\message{** patching of \string\beamer@@frametitle succeeded **}}%
{\message{** patching of \string\beamer@@frametitle failed **}}%

}{}

\makeatother


\begin{document}

\begin{frame}{Title}
Hello \pause world
\end{frame}
\end{document}

Responder1

Resposta principal

Em geral, corrigir comandos quando #envolvidos não pode acontecer no argumento de outro comando. Pode-se fazer alguns truques com códigos de categoria, mas outra abordagem pode ser mais fácil:

\documentclass{beamer}

\makeatletter
\@ifclassloaded{beamer}{\@tempswatrue}{\@tempswafalse}
\if@tempswa
  \usepackage{bookmark}
  \usepackage{etoolbox}
  \apptocmd{\beamer@@frametitle}
    {\only<1>{\bookmark[page=\the\c@page,level=3]{#1}}}%
    {\message{** patching of \noexpand\beamer@@frametitle succeeded **}}%
    {\message{** patching of \noexpand\beamer@@frametitle failed **}}%
\fi
\makeatother


\begin{document}

\begin{frame}{Title}
Hello \pause world
\end{frame}
\end{document}

A \if@tempswacondicional é uma condicional temporária fornecida pelo kernel.

Aqui está o que está escrito no .logarquivo:

** patching of \beamer@@frametitle succeeded **

Resposta generalizada

Uma abordagem semelhante sem usar \@tempswae que pode ser usada para outros pseudocondicionais LaTeX, como \@ifpackageloadedou \@ifundefined:

\makeatletter
\newcommand{\latex@conditional}[1]{#1{11}{01}}

\if\latex@conditional{\@ifclassloaded{beamer}}
  \usepackage{bookmark}
  \usepackage{etoolbox}
  \apptocmd{\beamer@@frametitle}
    {\only<1>{\bookmark[page=\the\c@page,level=3]{#1}}}%
    {\message{** patching of \noexpand\beamer@@frametitle succeeded **}}%
    {\message{** patching of \noexpand\beamer@@frametitle failed **}}%
%\else
% code for the false branch
\fi
\makeatother

Isso se baseia nos fatos que \ifexpandem os tokens e que os pseudocondicionais do LaTeX são totalmente expansíveis; então, no final, \ifencontra 11se a condição é verdadeira, caso contrário 01, segue os ramos verdadeiro e falso de acordo. Observe que tais construções podem ser aninhadas em outras condicionais do estilo TeX. O código para a ramificação falsa também pode ser especificado.

Método alternativo

Alternativamente, use o regexpatchpacote:

\documentclass{beamer}

\makeatletter
\@ifclassloaded{beamer}{
  \usepackage{bookmark}
  \usepackage{regexpatch}
  \xapptocmd{\beamer@@frametitle}
    {\only<1>{\bookmark[page=\the\c@page,level=3]{#1}}}%
    {\message{** patching of \noexpand\beamer@@frametitle succeeded **}}%
    {\message{** patching of \noexpand\beamer@@frametitle failed **}}%
}{}
\makeatother


\begin{document}

\begin{frame}{Title}
Hello \pause world
\end{frame}
\end{document}

informação relacionada