# Error when using defs inside a macro to write a row in a table

For the following MWE

\documentclass{article}

\newcommand{\cmd}[5]{%
\def\tA{#1}%
\def\tB{#2}%
\def\tC{#3}%
\def\tD{#4}%
\def\tE{#5}%

\tA & \tB & \tC & \tD & \tE \\
}

\begin{document}
\begin{tabular}{ccccc}
\cmd{1}{2}{3}{4}{5}
\end{tabular}
\end{document}


I keep getting the following error:

! Undefined control sequence.
\cmd ...}\def \tD {#4}\def \tE {#5}\par \tA & \tB
& \tC & \tD & \tE \\
l.15   \cmd{1}{2}{3}{4}{5}


Why doesn't it work?

PS. The reason for using \def is that in my document I need to handle more than 9 parameters to the command, and thus apply this method.

-
Can you show a real world example? Using more than nine arguments should be the very last resort; perhaps we can find a better way to input your text. –  egreg Apr 7 '14 at 16:21
It's for a paper where we have a table with over 9 columns. We haven't decided upon the exact order of the columns, but we don't want to have to rearrange all the arguments for every row. So that's why we're using a macro which takes all these column values as arguments. –  gablin Apr 7 '14 at 20:31
I said you that a better solution can be found. ;-) –  egreg Apr 7 '14 at 21:08

Cells inside a tabular form groups, so in your example the commands defined by \cmd are not available starting with the second cell. Solution: Use \gdef instead of \def in the definition of \cmd.

\documentclass{article}

\newcommand{\cmd}[5]{%
\gdef\tA{#1}%
\gdef\tB{#2}%
\gdef\tC{#3}%
\gdef\tD{#4}%
\gdef\tE{#5}%

\tA & \tB & \tC & \tD & \tE \\
}

\begin{document}
\begin{tabular}{ccccc}
\cmd{1}{2}{3}{4}{5}
\end{tabular}
\end{document}

-

You can avoid using many arguments. Here's an implementation of your \cmd where you specify the arguments as a comma separated list; with \selectorder you can decide what order is used in the output.

Note that \cmd will happily accept any number of items in the list; all you need is to specify the correct number of columns in the tabular and precede it with the suitable \selectorder command. I demonstrated this with two tables with four and five columns respectively.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\cmd}{m}
{
\gablin_cmd:n { #1 }
}

\NewDocumentCommand{\selectorder}{m}
{
\seq_gset_split:Nnn \g_gablin_order_seq { , } { #1 }
}

\prop_new:N \l_gablin_arg_prop
\seq_new:N \l_gablin_output_seq
\seq_new:N \g_gablin_order_seq
\int_new:N \l_gablin_input_int

\cs_new_protected:Npn \gablin_cmd:n #1
{
% clear the variables' contents (it isn't really necessary)
\prop_clear:N \l_gablin_arg_prop
\seq_clear:N \l_gablin_output_seq
\int_zero:N \l_gablin_input_int
% map through the items in the argument
\clist_map_inline:nn { #1 }
{
% the integer variable is used to number the items
\int_incr:N \l_gablin_input_int
% items are stored in a property list
\prop_put:Nfn \l_gablin_arg_prop { \int_to_arabic:n { \l_gablin_input_int } } { ##1 }
}
% map through the items stating the order of items in columns
\seq_map_inline:Nn \g_gablin_order_seq
{
% put the items in a new sequence
\seq_put_right:Nx \l_gablin_output_seq
{
\prop_get:Nn \l_gablin_arg_prop { ##1 }
}
}
% use the sequence, separating arguments with &
\seq_use:Nn \l_gablin_output_seq { & }
}

% we need a variant of \prop_put:Nnn store a number in the key
\cs_generate_variant:Nn \prop_put:Nnn { Nf }

\ExplSyntaxOff

\begin{document}

\selectorder{1,2,3,4}

\begin{tabular}{*{4}{c}}
\cmd{ba,bb,bc,bd} \\
\cmd{ca,cb,cc,cd} \\
\end{tabular}

\bigskip

\selectorder{5,4,3,2,1}

\begin{tabular}{*{5}{c}}

The setting defined by \selectorder will remain valid until countermanded by another choice and is global, so it doesn't matter if it's issued in a table environment. So this code is very flexible.
Note that as of September 2014, \prop_get:Nn has been renamed to \prop_item:Nn –  egreg Sep 17 '14 at 18:00