多年来,我很高兴将这两者一起使用,将其fmtcount
包含在\RequirePackage
我的类定义中,并将其作为文档文件本身longtable
包含其中。\usepackage
但由于我使用得longtable
相当多,我决定将其移到我的类定义文件中。结果出现了错误。这是一个非常基本的精简示例。类定义文件是:
\ProvidesClass{TableExample}
\RequirePackage{fmtcount}
\RequirePackage{longtable}
\PassOptionsToClass{a4paper}{article}
\ProcessOptions
\LoadClass{article}
那么使用它的文档是:
\documentclass{TableExample}
\begin{document}
Useless text.
\end{document}
当遵守 pdflatex 时,会产生以下错误:
! LaTeX Error: Command \c@table already defined.
Or name \end... illegal, see p.192 of the manual.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.463 \newcounter{table}
我很惊讶,因为我多年来一直一起使用它们,只是fmtcount
在类定义文件和longtable
文档本身中使用。所以我想也许存在某种范围问题 - 如果重新定义不发生在处理的同一阶段,那么重新定义也许是允许的,也许吧?(那么,是在处理类定义文件之前,还是之后?)但经过一些实验,我发现这个文件编译起来毫无困难。
\documentclass[a4paper]{article}
\usepackage{fmtcount}
\usepackage{longtable}
\begin{document}
Useless text.
\end{document}
我搜索了一下,发现一些链接指出\RequirePackage
和之间唯一真正的区别\usepackage
是\RequirePackage
可以在命令之前发出\documentclass
,但这里不是这种情况。所以我很困惑为什么这两个包在两个连续的命令中包含时共存,但在两个连续的命令\usepackage
中包含时却发生冲突。\RequirePackage
不管怎样,我从来不会在文档的同一部分使用这两个包(例如,我从来不会在 中使用fmtcount
中的功能longtable
),但我想如果我这样做的话可能会有麻烦。还没有尝试过。
一种补救措施是保持原样,因为它们似乎不会造成问题,并且继续将其包含longtable
在我的文档文件中,而不是类定义中。我只是想知道为什么会出现这种奇怪的行为。
答案1
正如 @moewe 在回答,您遇到的问题与该包无关。相反,它仅与正在加载fmtcount
该包这一事实有关longtable
前而不是在article
文档类文件加载后。该文件longtable.sty
包含以下代码块:
\ifx\c@table\undefined
\newcounter{table}
\def\fnum@table{\tablename~\thetable}
\fi
即,执行测试以查看是否table
存在名为的计数器变量;如果不存在,则通过语句创建此计数器\newcounter
。(代码还创建了一个名为的宏\fnum@table
,但这与此无关。)人们只能推测作者包中的longtable
某些部分出于谨慎而选择插入此块,以防止不幸的用户使用某些令人讨厌的文档类,而这些文档类由于不可知的原因不提供名为 的计数器table
。(我想这包括文档类,顾名思义,它永远不应该用于创建“真实”文档。当然,我无法预见为什么有人希望使用文档类minimal
来创建while 。)longtable
minimal
你现在可能已经猜到了,article
文档类做定义一个名为的计数器table
,通过(还有什么方法?)
\newcounter{table}
语句。请注意,没有采取任何预防措施来article.cls
检查名为的计数器变量是否table
已定义。结果,LaTeX 内核会发出错误消息并自行终止。我认为可以公平地说,文档类article
(以及其他“标准”LaTeX 文档类,例如report
和book
)的作者根本没有预料到table
加载定义计数器的包的意外情况前文档类已加载。
你还表示
我进行了一些搜索,发现一些链接指出
\RequirePackage
和之间唯一真正的区别\usepackage
是\RequirePackage
可以在命令之前发出\documentclass
......
这个说法部分正确,因为它依赖于“可以发出”这个含糊其辞的动词。但是,推断在文档类文件之前或之后加载给定包不会产生任何后果是不正确的。否则,为什么还要区分\RequirePackage
和\usepackage
——为什么不加载所有包前加载文档类?正如您通过艰苦的努力发现的那样,确实存在一些“真正的差异”……
这个故事的寓意是什么?在你自己间接加载文档article
类的文档类中,你应该养成加载所有包的习惯后以下代码块:
\PassOptionsToClass{a4paper}{article}
\ProcessOptions
\LoadClass{article}
除非您有充分的理由在加载article
文档类之前加载包。什么是“充分的理由”?@egreg在评论中指出,“软件包应该在之前\LoadClass
或之前加载\LoadPackage
仅在设置与类或包选项相关的代码时才需要“[强调] 据我所知,这样的包裹很少。其中一个包裹是fixltx2e,其中包含 1994 年至 2015 年期间发现的对 LaTeX 内核的各种修复。如果您的 LaTeX 内核比 2015/11/30 更新,则没有必要(甚至不建议!)加载此包。
答案2
可以使用以下方法重现相同的问题
\RequirePackage{longtable}
\documentclass[a4paper]{article}
\begin{document}
Useless text.
\end{document}
longtable.sty
如果计数器table
未定义,则定义它。但随后该类article
也会尝试定义table
计数器。
longtable
解决方案是在(真实)文档类之后加载。因此您的.cls
代码可能看起来像
\ProvidesClass{TableExample}
\PassOptionsToClass{a4paper}{article}
\ProcessOptions
\LoadClass{article}
\RequirePackage{fmtcount}
\RequirePackage{longtable}