What is wrong with this TeX macro

After \\ (which expands amongst other things to the primitive \cr that ends a table row, TeX looks ahead using expansion only to see if the table cell needs special treatment, specifically it looks for \noalign \span or omit. As soon as it finds a non-expandable token that is not one of these it stops and processes the cell normally.

so if you put \mycline at the start of a row it is expanded one level and then the next token that is seen is the \xdef which is not expandable so after that it is not possible to have any spanning entries (which are needed for \cline \cmidrule \multicolumn and other similar constructs).

If you look how these things are coded in table packages you will see that either they have to work purely by expansion (so no \xdef or foreach etc) or they have to start a \noalign, do all the computation in the local scope of \noalign and then globally insert the expandable commands to span the columns after the \noalign has finished.


As Joseph comments, there's no point in saying

\cmidrule{1-1}\cmidrule{2-2}\cmidrule{3-3}

because the effect is the same as saying

\cmidrule{1-3}

If you want to use the "shortening" feature of \cmidrule and generate

\cmidrule(lr){1-1}\cmidrule(lr){2-2}\cmidrule(lr){3-3}

then you can do the computations in a \noalign and then deliver the result:

\documentclass{article}
\usepackage{pgffor}
\usepackage{booktabs}
\makeatletter
\def\mycline(#1-#2){\noalign{
  \gdef\@mycline{}%
  \foreach \a in {#1,...,#2}{%
    \edef\@tempa{\noexpand\cmidrule(lr){\a-\a}}%
    \expandafter\g@addto@macro\expandafter\@mycline\expandafter{\@tempa}%
  }}
  \@mycline
}


% the macro
\begin{document}
\begin{tabular}{llll}
1&2&3&4\\ \mycline(1-3)
5&6&7&8\\
\end{tabular}
\end{document}

enter image description here

Notice some points:

  1. You have to say \noexpand\cmidrule in the \edef

  2. Using \g@addto@macro is a more economic way to add tokens to a parameterless macro

  3. Using a @-command such as \@mycline is better than \MC that could clobber some already existing macro

  4. Using \noalign ensures that the work is done "outside any alignment cell"