1

The following works as intended, removing the vlines from the top row of a LaTeX longtable. Note: Need to use longtable because this table spans multiple pages and nicematrix does not currently support spanning multiple pages.

\documentclass{article}
\usepackage{longtable}

\makeatletter \newcommand{@mc}[1]{\multicolumn{1}{l}{#1}} \newcommand{\titleRow}[3]{@mc{when} & @mc{#1} & @mc{#2} & @mc{#3}\[1pt]} \makeatother

\begin{document} \begin{longtable}[c]{|p{3cm}|p{3cm}|p{3cm}|p{3cm}|}
\titleRow{First}{Second}{Third}
\hline
January & Tom & Dick & Harry \\hline February & Dick & Harry & Tom \\hline \end{longtable} \end{document}

Here is the output as expected: enter image description here

However, making the \titleRow command in a starred version leads to a Misplaced \omit. \multispan -> \omit error. Why does the following not work as intended?

\documentclass{article}
\usepackage{longtable}

\makeatletter \newcommand{@mc}[1]{\multicolumn{1}{l}{#1}} \newcommand{\titleRow}{@ifstar\star@titleRow\nostar@titleRow} \newcommand{\star@titleRow}[3]{@mc{when} & @mc{#1} & @mc{#2} & @mc{#3}\[1pt]} \newcommand{\nostar@titleRow}[3]{@mc{} & @mc{#1} & @mc{#2} & @mc{#3}\[1pt]} \makeatother

\begin{document} \begin{longtable}[c]{|p{3cm}|p{3cm}|p{3cm}|p{3cm}|}
\titleRow{First}{Second}{Third}
\hline
January & Tom & Dick & Harry \\hline February & Dick & Harry & Tom \\hline \end{longtable} \end{document}

2 Answers2

2

The problem is, that the \multicolumn macro (which expands to the right number of \omit\span primitives) must be first object in the table cell after expansion. Because \halign primitive (LaTeX tables use it) looks to the table cell data and runs expand processor here until first non-expandable and non-space item is found here. If it is \omit then \halign omits the preamble for this cell. In other cases the left part of the preamble of given cell is used, then data from the cell and then right part of the preamble.

The \@ifstar LaTeX macro uses \futurelet TeX primitive and it is non-expandable. So the cell is not expanded to the \multicolumn macro, i.e. to the \omit. If the \omit is encountered in another context (i.e. in the middle of the cell) then TeX reports error.

The solution is based on using \omit primitive directly before \@ifstar, because we know that \omit will be used in both cases (stared and non-stared). Of course, we need not to use \multicolumn in the fist cell in this case, because \omit is used already.

\newcommand{\@mc}[1]{\multicolumn{1}{l}{#1}}
\newcommand{\titleRow}{\omit\@ifstar\star@titleRow\nostar@titleRow}
\newcommand{\star@titleRow}[3]{\enspace when\hfil & \@mc{#1} & \@mc{#2} & \@mc{#3}\\[1pt]}
\newcommand{\nostar@titleRow}[3]{ & \@mc{#1} & \@mc{#2} & \@mc{#3}\\[1pt]}
wipet
  • 74,238
1

longtable or tabular or any other table making environment is not the problem; TeX expands tokens at the beginning of a table row in order to see whether \omit comes along and stops the search as soon as it finds an unexpandable command that isn't \omit.

OK, what's \omit that you never saw? It's the primitive command that tells TeX to ignore the template for a specific column in an alignment. And \multicolumn starts with \omit. But \@ifstar doesn't.

Use an expandable version for your *-command.

\documentclass{article}
\usepackage{longtable}

\NewExpandableDocumentCommand{\titleRow}{smmm}{% \multicolumn{1}{l}{\IfBooleanF{#1}{when}} & \multicolumn{1}{l}{#2} & \multicolumn{1}{l}{#3} & \multicolumn{1}{l}{#4} \[1pt] }

\begin{document}

\begin{longtable}[c]{|p{3cm}|p{3cm}|p{3cm}|p{3cm}|}
\titleRow{First}{Second}{Third}
\hline January & Tom & Dick & Harry \\hline February & Dick & Harry & Tom \\hline \end{longtable}

\bigskip

\begin{longtable}[c]{|p{3cm}|p{3cm}|p{3cm}|p{3cm}|}
\titleRow*{First}{Second}{Third}
\hline January & Tom & Dick & Harry \\hline February & Dick & Harry & Tom \\hline \end{longtable}

\end{document}

enter image description here

egreg
  • 1,121,712