3

I am creating my CV with LaTeX on Overleaf. I defined a custom command \cvpub in my .cls file to typeset publication entries. It takes 8 arguments (tag, authors, title, venue, year, conference, DOI, award).

Here is the definition:

\newcommand{\cvpub}[8]{%
  \noindent
  \begin{tabular}{@{}p{2em}@{\hspace{1em}}p{0.85\linewidth}}%
    \textcolor{black}{#1} % Tag
    & #2 \\ % Authors
    & \textbf{#3} \\ % Title
    & \textit{#4}, #5 #6 \\ % Venue + Year
    \ifx&#7&% If DOI is empty
      \ifx&#8& % If Award is empy
        % Both DOI and Award are empty: do nothing
      \else % If Award is not empty (and DOI is not empty)
        & \textbf{\textcolor{black}{#8}} \\ % Award
      \fi
    \else % If DOI is not empty
      \ifx&#8&% If Award is empty
        & \textnormal{doi: #7} % DOI
      \else %If DOI is not empty and Award is not empty
        & \textnormal{doi: #7}, \textbf{\textcolor{black}{#8}} \\ % DOI, Award
      \fi
    \fi
  \end{tabular}%
}

When I use \cvpub in cv.tex, if the DOI exists but the award does not, it causes an error.

For example, in the following code from cv.tex, P1 and P2 work correctly, but P3 does not. What’s particularly confusing is that the DOI shows up twice in P3.

Output PDF:

Error Example

Code:

\cvpub % Works well
{P1} 
{Author, Author, Author} %Authors
{Title}  %Title
{Journal name} %Venue
{2025} %Year
{(Conference))} %Conference tag
{} %DOI
{Award} %Award

\cvpub  % Works Well
{P2}
{Author, Author, Author} %Authors
{Title}  %Title
{Journal name} %Venue
{2025} %Year
{(Conference))} %Conference tag
{} %DOI
{} %Award

\cvpub{P3}  % Does Not Work
{Author, Author, Author} %Authors
{Title}  %Title
{Journal name} %Venue
{2025} %Year
{(Conference))} %Conference tag
{10.1111/XXXX.1234.56789} %DOI
{} %Award %Line 94

Overleaf errors:

Incomplete \ifx; all text was ignored after line 94.
Missing } inserted.
Extra alignment tab has been changed to \cr.
Extra \fi.
Underfull \hbox (badness 10000) in paragraph at lines 94--94
Overfull \hbox (88.24603pt too wide) in paragraph at lines 94--94

Question: Why does case P3 (DOI present but Award empty) fail? How should I revise this macro to make it works in all three cases (DOI only, Award only, or both)?

4
  • 1
    Use another token instead of & for the \ifx&#1& empty test (eg \ifx\relax#1\relax). Commented Sep 16 at 1:13
  • 1
    welcome! \ifx tests the expansion the tokens and & will not expand to something it likes inside a tabular. if you still have problems, please provide complete but minimal code we can compile to reproduce the problem. Commented Sep 16 at 1:20
  • 2
    I would recommend considering a key/value interface. 8 inputs is a lot to keep in order. Commented Sep 16 at 2:46
  • Note that the kernel provides \IfBlankTF{arg}{true code}{false code}. Commented Sep 16 at 6:42

2 Answers 2

3

Testing for emptiness is best not done with \ifx:

\if\relax\detokenize{#1}\relax

is a much robust choice.

On the other hand, I'd go with a key=value syntax, which is easier to maintain, because remembering the order of eight arguments is difficult.

\documentclass{article}
\usepackage{array,xcolor}

\ExplSyntaxOn
\NewDocumentCommand{\cvpub}{mm}
 {% #1 = tag, #2 = keys
  \group_begin:
  \keys_set:nn { hesper/cvpub } {#2}
  \hesper_cvpub:n {#1}
  \group_end:
 }

\keys_define:nn { hesper/cvpub }
 {
  authors    .tl_set:N = \l_hesper_cvpub_authors_tl,
  title      .tl_set:N = \l_hesper_cvpub_title_tl,
  venue      .tl_set:N = \l_hesper_cvpub_venue_tl,
  year       .tl_set:N = \l_hesper_cvpub_year_tl,
  conference .tl_set:N = \l_hesper_cvpub_conference_tl,
  doi        .tl_set:N = \l_hesper_cvpub_doi_tl,
  awards     .tl_set:N = \l_hesper_cvpub_awards_tl,
 }

\cs_new_protected:Nn \hesper_cvpub:n
 {
  \par\addvspace{\medskipamount}\noindent
  \begin{tabular}{@{}w{l}{2em}@{\hspace{1em}}p{\dim_eval:n {\linewidth-3em}}@{}}
    \textcolor{black}{#1} % Tag
    & \l_hesper_cvpub_authors_tl \\ % Authors
    & \textbf{\l_hesper_cvpub_title_tl} \\ % Title
    & \textit{\l_hesper_cvpub_venue_tl},~ % venue
      \l_hesper_cvpub_year_tl
      \tl_if_blank:VF \l_hesper_cvpub_conference_tl {~(\l_hesper_cvpub_conference_tl)}
    \\
    \tl_if_blank:VTF \l_hesper_cvpub_doi_tl
     {% no DOI
      \tl_if_blank:VF \l_hesper_cvpub_awards_tl
       {% there are awards
        & \textbf{\textcolor{black}{\l_hesper_cvpub_awards_tl}} \\ % Award
       }
     }
     {% with DOI
      & \textnormal{doi:~\l_hesper_cvpub_doi_tl} % DOI
        \tl_if_blank:VF \l_hesper_cvpub_awards_tl
         {
          \textbf{,~\textcolor{black}{\l_hesper_cvpub_awards_tl}}
         }
      \\
     }
  \end{tabular}
 }
\ExplSyntaxOff

\begin{document}

\iffalse % the template to copy
\cvpub{<tag>}{
  authors=,
  title=,
  venue=,
  year=,
  conference=,
  doi=,
  awards=,
}
\fi

\cvpub{P1}{
  authors={Author One, Author Two},
  title=Title,
  venue=Journal name,
  year=2025,
  conference=Conference,
  awards=Award,
}

\cvpub{P2}{
  authors=Author Single,
  title=Title,
  venue=Journal name,
  year=2025,
  doi=10.1111/XXXX.1234.56789,
}
\cvpub{P3}{
  authors=Author Single,
  title=Title,
  venue=Journal name,
  year=2025,
  doi=10.1111/XXXX.1234.56789,
  awards=Award,
}

\end{document}

If there are commas in a value, like in P1, brace it.

output

1

The error happens because macro used \ifx&#7& to test whether an argument is empty. As @plante and @cfr pointed out in their comments, inside a tabular, & is a column separator, so \ifx cannot handle it properly.

The solution is to use another token as the sentinel, e.g. \relax.

Here is the corrected macro:

\newcommand{\cvpub}[8]{%
  \noindent
  \begin{tabular}{@{}p{2em}@{\hspace{1em}}p{0.85\linewidth}}%
    \textcolor{black}{#1} & #2 \\ % Authors
    & \textbf{#3} \\ % Title
    & \textit{#4}, #5 #6 \\ % Venue + Year
    \ifx\relax#7\relax
      \ifx\relax#8\relax
      \else
        & \textbf{\textcolor{black}{#8}} \\
      \fi
    \else
      \ifx\relax#8\relax
        & \textnormal{doi: #7} \\
      \else
        & \textnormal{doi: #7}, \textbf{\textcolor{black}{#8}} \\
      \fi
    \fi
  \end{tabular}%
}

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.