Making modifications to numbering in \ref when overwriting \caption

I'm using this answer to control the appearance and order of float captions in a document. The relevant part is:

\renewcommand{\thetable}{S\arabic{table}}
\usepackage{tocloft}
\makeatletter
\newcommand{\listfloatname}{\normalsize Contents:}
\newlistof{float}{flt}{\listfloatname}
\long\def\@caption#1[#2]#3{%
\par
\refstepcounter{float}%
{\protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}}%
{\protect\numberline{\csname the#1\endcsname}{ #2}}%
\begingroup
\@parboxrestore
\if@minipage
\@setminipage
\fi
\normalsize
\@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
\endgroup}
\makeatother


This is used to label floats in order of appearance in a certain document. However, when I try and use \ref to reference a float, the additional S character does not appear. It works perfectly if I remove the above section, but I need to retain the functionality.

Here is a MWE:

\documentclass{article}
\usepackage{tocloft}
\renewcommand{\thetable}{S\arabic{table}}
%% TOC handling
\makeatletter
\newcommand{\listfloatname}{\normalsize Contents:}
\newlistof{float}{flt}{\listfloatname}
\long\def\@caption#1[#2]#3{%
\par
\refstepcounter{float}%
{\protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}}%
{\protect\numberline{\csname the#1\endcsname}{ #2}}%
\begingroup
\@parboxrestore
\if@minipage
\@setminipage
\fi
\normalsize
\@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
\endgroup}
\makeatother

\begin{document}
\begin{table}
\caption[Short title]{A table \label{table:a_label}}
\begin{tabular}{c|c}
1 & 2 \\
3 & 4
\end{tabular}
\end{table}
As in \ref{table:a_label}
\end{document}

• As I can see the \@caption is totally changed for all floats then? Why should \thetable be called by your 'float' counter caption at all? This is weird! – user31729 Jan 4 '17 at 17:35
• @ChristianHupfer I confess I don't really understand how the \caption is redefined. It is supposed to count the total number of floats, so that it can produce a sorted contents list in order of appearance in the document. But the caption label (in the table) does have the S, so it must call the \thetable... – JP Janet Jan 4 '17 at 17:54
• With 'order of appearance' you mean the order in the output document, not in the order of specification? – user31729 Jan 4 '17 at 19:27
• Yes, in the output document. I needed to make a single contents list for all floats, in the order in which they appear in the final document. I got this code from Jagath's answer to the linked question, and it does exactly what is required, but it breaks \ref – JP Janet Jan 4 '17 at 19:34
• The answer is quite easy (after thinking :D) – user31729 Jan 4 '17 at 19:40

This took me some minutes to understand why the reference is wrong.

Well, the table counter is increased already by the \caption command, before \@caption is called, so \refstepcounter{float} will overwrite the \@currentlabel definition, which is used by \label to write the relevant information to the .aux file.

Solution: As long as your particular float shall not be referred to as float don't use \refstepcounter but \stepcounter.

\documentclass{article}
\usepackage{tocloft}
\renewcommand{\thetable}{S\arabic{table}}
%% TOC handling
\makeatletter
\newcommand{\listfloatname}{\normalsize Contents:}
\newlistof{float}{flt}{\listfloatname}
\long\def\@caption#1[#2]#3{%
\par
\stepcounter{float}% No refstepcounter here!
{\protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}}%
{\protect\numberline{\csname the#1\endcsname}{ #2}}%
\begingroup
\@parboxrestore
\if@minipage
\@setminipage
\fi
\normalsize
\@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
\endgroup}
\makeatother

\begin{document}
\listoffloat
\begin{table}
\caption[Short title]{A table \label{table:a_label}}
\begin{tabular}{c|c}
1 & 2 \\
3 & 4
\end{tabular}
\end{table}
As in \ref{table:a_label}
\end{document}


If the only thing you're doing is creating a .flt file to contain each of your floats (perhaps a combination of figures and/or tables), you don't have to redefine the entire \@caption. Instead, insert the relevant contents addition using an etoolbox patch; it's much cleaner:

\documentclass{article}

\usepackage{tocloft,etoolbox}

\renewcommand{\thetable}{S\arabic{table}}

\newcommand{\listfloatname}{\normalsize Contents:}
\newlistof{float}{flt}{\listfloatname}

\makeatletter
\patchcmd{\@caption}% <cmd>
{}{}% <success><failure>
\makeatother

\begin{document}

\listoffloat

\begin{table}
\centering
\caption[Short title]{A table \label{table:a_label}}
\begin{tabular}{c|c}
1 & 2 \\
3 & 4
\end{tabular}
\end{table}
As in \ref{table:a_label}.

\end{document}


You may even get away with adapting \addcontentsline to insert content into an .flt file every time it is sent content that should go into the .lof or .lot:

\documentclass{article}

\usepackage{tocloft}

\renewcommand{\thetable}{T\arabic{table}}
\renewcommand{\thefigure}{F\arabic{figure}}

\newcommand{\listfloatname}{\normalsize Contents:}
\newlistof{float}{flt}{\listfloatname}

\ifnum\pdfmatch{#1}{lot,lof}=1 % A table or figure...
\fi
}

\begin{document}

\listoffloat

\section{A section}

A table~\ref{tbl:table} and figure~\ref{fig:figure}.

\begin{table}
\centering
\caption[Short title]{A table \label{tbl:table}}
\end{table}

\begin{figure}
\centering
\caption[Short figure]{A Figure \label{fig:figure}}
\end{figure}

\end{document}