8

I'm using a custom command to format all tables in a document. Some tables share properties other than style, such as column definitions and headers, which is why this answer inspired me to even more reduce repeated code.

Inserting header data into the table command did not cause any problems, while for inserting column definitions I had to find out how to expand the column definitions before insertion. \expandafter solved that problem.

Now, I'd like to combine parameters given as commands and others given as literals, e.g. the table's data. If the to-be-expanded command that contains the column definitions happens to be the first argument, this works fine. What do I need to do if conversely a literal is the first argument? How do I make \expandafter bypass a pair of curly braces instead of a command?

 

\documentclass{article}
\usepackage{booktabs}

\begin{document}

    \newcommand{\colDef}{{cc}}  
    \newcommand{\tableBody}{a & b\\}

    \newcommand{\myTabA}[2]{%
        \begin{tabular}{#1}
            1 & 2\\\midrule
            #2
        \end{tabular}       
    }

    %same command with #1 and #2 switched
    \newcommand{\myTabB}[2]{%
        \begin{tabular}{#2}
            1 & 2\\\midrule
            #1
        \end{tabular}       
    }       

    %draw table A
    \expandafter\myTabA\colDef{\tableBody}
    \expandafter\myTabA\colDef{c & d\\} 

    %draw table B
    \expandafter\myTabB\expandafter\tableBody\colDef

    %produces error
    %\expandafter\myTabB\expandafter{c & d\\}\colDef    

\end{document}
dgs
  • 2,741

3 Answers3

10

It's simpler of you push the expansion control into the macro, so it always expands the first token of #2 once, then you don't need \expandafter in the document.

\documentclass{article}
\usepackage{booktabs}

\begin{document}

    \newcommand{\colDef}{{cc}}  
    \newcommand{\tableBody}{a & b\\}

    \newcommand{\myTabA}[2]{%
        \begin{tabular}{#1}
            1 & 2\\\midrule
            #2
        \end{tabular}       
    }

    %same command with #1 and #2 switched
    \newcommand{\myTabB}[2]{%
        \def\temp{\begin{tabular}}%
           \expandafter\temp\expandafter{#2}
            1 & 2\\\midrule
            #1
        \end{tabular}       
    }       

    %draw table A
    \expandafter\myTabA\colDef{\tableBody}
    \expandafter\myTabA\colDef{c & d\\} 

    %draw table B
    \myTabB\tableBody\colDef

    %produces error (not now!)
    \myTabB{c & d\\}\colDef    

\end{document}
David Carlisle
  • 757,742
8

The etextools package provides some tools for doing this, for example

\ExpandNextTwo{code}{arg 1}{arg 2}

as used below:

\documentclass{article}
\usepackage{booktabs}
\usepackage{etextools}

\begin{document}

   \newcommand{\colDef}{{cc}}  
   \newcommand{\tableBody}{a & b\\}

   \newcommand{\myTabA}[2]{%
    \begin{tabular}{#1}
        1 & 2\\\midrule
        #2
    \end{tabular}       
}

%same command with #1 and #2 switched
\newcommand{\myTabB}[2]{%
    \begin{tabular}{#2}
        1 & 2\\\midrule
        #1
    \end{tabular}       
}       

%draw table A
\expandafter\myTabA\colDef{\tableBody}
\expandafter\myTabA\colDef{c & d\\} 

%draw table B
\expandafter\myTabB\expandafter\tableBody\colDef

% no longer produces error
\ExpandNextTwo{\myTabB}{c & d\\} \colDef

\end{document}
Scott H.
  • 11,047
2

I've ended up using an etextools command inside the tabular definition, thus drawing from both all answers.

\newcommand{\myTabB}[2]{%
    \expandnext{
    \begin{tabular}}{#2}
        1 & 2\\\midrule
        #1
    \end{tabular}       
}   
dgs
  • 2,741