如果给定的宏未定义,则通过宏定义宏

如果给定的宏未定义,则通过宏定义宏

如果尚未定义宏,我想定义一个宏。我可以按照下面的示例内联执行此操作。但我希望有一个宏可以帮我实现此功能。我尝试让它工作DefineMacroIfUndefined,但不确定如何调整它以使其工作。

我已经注释掉了对它的调用,DefineMacroIfUndefined因为否则无法编译。

\documentclass{article}

\newcommand{\CheckIfCommandDefined}{
    \ifdefined\MyNewCommand
        MyNewCommand is defined.\par%
    \else
        MyNewCommand is not defined.\par%
    \fi
}

% Define macro to the given value if not already defined
\newcommand{\DefineMacroIfUndefined}[2]{
% #1 is name of macro
% #2 is value to be assigned if this macros is not already defined.
\ifdefined\csname#1\endcsname
    % Do nothing since it is already defined
\else
    \newcommand{\csname#1\endcsname}{#2}
\fi
}

\begin{document}

% This works great.
\ifdefined\MyNewCommand
    % Do nothing since it is already defined
\else
    \newcommand{\MyNewCommand}{true}
\fi

\CheckIfCommandDefined
\let\MyNewCommand\undefined % Undefine \MyNewCommand

\CheckIfCommandDefined
% But want to be able to do the above thru a macro
%\DefineMacroIfUndefined{MyNewCommand}{true}
\CheckIfCommandDefined

\end{document}

答案1

您可以简单地使用\providecommand而不是\newcommand。它具有相同的语法,但仅在尚未定义时才定义宏。


如果您想手动执行此操作,则需要\expandafter在之前使用\newcommand以确保\csname ...\endcsname在它之前展开。在这种情况下,{ }应该简单地删除。

% Define macro to the given value if not already defined
\newcommand{\DefineMacroIfUndefined}[3][0]{%
% #1 is the optional argument
% #2 is name of macro
% #3 is value to be assigned if this macros is not already defined.
\ifcsname#2\endcsname
    % Do nothing since it is already defined
\else
    \expandafter\newcommand\csname#2\endcsname[#1]{#3}%
    %or: \expandafter\newcommand\expandafter{\csname#2\endcsname}[#1]{#3}%
\fi
}

答案2

以下是我使用的一整套宏。它具有完整的错误检查功能,并将所有内容写入日志文件!!!如果您尝试覆盖现有命令,它将因错误而停止。

它给你三个命令\TestedNameLet\TestedNameDef并且\TestedNameRobustDef

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatletter

% You will probably put this inside a package
\newcommand*\my@pkgname{mypackage}

\def\my@ifundefined#1{%-- Better than standard latex (eTex has better tests than this)
   \begingroup\expandafter\expandafter\expandafter\endgroup
   \expandafter\ifx\csname#1\endcsname\relax
       \expandafter\@firstoftwo
   \else
       \expandafter\@secondoftwo
   \fi}

\long\def\my@ifnamedefinable #1{%-- Test and write info to log
    \edef\reserved@a{#1}%
    \my@ifundefined\reserved@a
       {\edef\reserved@b{\expandafter\@carcube \reserved@a xxx\@nil}%
       \ifx \reserved@b\@qend \my@notdefinable\else
          \ifx \reserved@a\@qrelax \my@notdefinable\else
            \PackageInfo{\my@pkgname}{\@backslashchar\reserved@a\space created}%
          \fi
       \fi}%
    \my@notdefinable}

\gdef\my@notdefinable{%-- Error message
   \PackageError{\my@pkgname}{%
      Command \@backslashchar\reserved@a\space
      already defined.\MessageBreak
      Or name \@backslashchar\@qend... illegal.%
      }{%
      If \@backslashchar\reserved@a\space is not important\MessageBreak
      then \protect\let\@backslashchar\reserved@a%
      =\protect\relax,\MessageBreak
      else use a different \@backslashchar name.}}

%%% Base level commands %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand*{\my@namelet}[1]{\expandafter\let\csname #1\endcsname}
\newcommand*{\my@nameuse}[1]{\csname #1\endcsname}
\newcommand*{\my@namedef}[1]{\expandafter\def\csname #1\endcsname}
\newcommand*{\my@robustnamedef}[1]{%
   \expandafter\edef\csname #1\endcsname{%
      \noexpand\protect\my@nameuse{#1 }}%
   \my@namedef{#1 }}

%%% These are the commands to use %%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand*{\TestedNameLet}[1]{%
   \my@ifnamedefinable{#1}\my@namelet{#1}}

\newcommand*{\TestedNameDef}[1]{%
   \my@ifnamedefinable{#1}\my@namedef{#1}}

\newcommand*{\TestedNameRobustDef}[1]{%
   \my@ifnamedefinable{#1}\my@robustnamedef{#1}}

\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

使用示例如下:

\newcommand\CreateRef[2]{%
    \TestedNameDef{#1Ref}##1{#2\ref{##1}}}

这可用于动态创建你自己的参考命令

\CreateRef{Fig}{Figure~}

这将创建一个命令\FigRef{lab} -> Figure~\ref{lab}

相关内容