Who ate my space? (How to stop \exp_args:Nf from consuming a space?)

I would simply use the new e-type approach here (i.e. using the \expanded primitive or equivalent):

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \__printf_pre_output:n #1 { [ \tl_to_str:n {#1} ] }
\cs_set:Npn \__printf_tmp:w #1
  {
    \cs_new:Npn \__printf_format_final_print:n ##1
      {
        \exp_args:Ne \__printf_pre_output:n
          { \prg_replicate:nn {##1} {#1} }
      }
  }
\__printf_tmp:w { ~ }
\ttfamily
Wrong,~4~spaces:~\__printf_format_final_print:n {5}\par
Right,~5~spaces:~[\ \ \ \ \ ]\par
\ExplSyntaxOff
\end{document}

This will likely become the standard approach for such cases: f-type expansion is much less important now that we have e-type either directly using the \expanded primitive or (where necessary) emulated. Note that MiKTeX already has \expanded in pdfTeX and XeTeX, and that this will appear in TeX Live 2019. Also note that LuaTeX has had \expanded from day one. (Emulation is reliable but does have a performance impact: at present, it probably is best avoided for any code which needs to work in tight loops or similar.)


Like @jfbu mentioned, expanding twice is enough for \prg_replicate:nn. So using \exp_args:No twice on it suffices:

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \__printf_pre_output:n #1 { [ \tl_to_str:n {#1} ] }
\cs_set:Npn \__printf_tmp:w #1
  {
    \cs_new:Npn \__printf_format_final_print:n ##1
      {
        \exp_args:NNo \exp_args:No \__printf_pre_output:n
          { \prg_replicate:nn {##1} {#1} }
      }
  }
\__printf_tmp:w { ~ }
\ttfamily
Wrong,~4~spaces:~\__printf_format_final_print:n {5}\par
Right,~5~spaces:~[\ \ \ \ \ ]\par
\ExplSyntaxOff
\end{document}

I can only second @JosephWright and @Skillmon answers but speaking of what I know, with xint you only need to expand once \romannumeral\xintreplicate{100}{ } to get 100 spaces. So if inside a macro

\def\x{\romannumeral\xintreplicate{100}{ }}

you only need to expand \x twice.

Or

\def\x{\xintreplicate{100}{ }}

then you can do \romannumeral\x.

Oh wait, I completely forgot: \romannumeral\xintreplicate basically IS (up to different user interface) \prg_replicate:nn, I COPIED its underlying implementation ;-).