The following defines the macro \getnumargs which takes two arguments. The first is an arbitrary macro, the second the macro which should store the result.
It'll store the number of arguments taken by the first macro in the second.
Caveat: This only gets how many arguments exactly that macro will take, not more not less. It'll also fail if the macro takes delimited arguments. A few examples where it is technically right, but most likely doesn't return what you had in mind are included.
\documentclass[]{article}
\makeatletter
\edef\getnumargs@ifmacro
{%
\noexpand\expandafter\noexpand\getnumargs@ifmacro@
\noexpand\getnumargs@meaning\relax\noexpand\getnumargs@ifmacro@true
\detokenize{macro:}\relax\noexpand\getnumargs@ifmacro@false
}
\def\getnumargs@ifmacro@true#1\getnumargs@ifmacro@false#2{#2}
\expandafter\def\expandafter\getnumargs@ifmacro@
\expandafter#\expandafter1\detokenize{macro:}#2\relax
{}
\newcommand*\getnumargs@ifmacro@false[1]
{%
\PackageError{Alex}{}{Not a macro!}%
\def\getnumargs@num{0}%
}
\newcommand\getnumargs[2]
{%
\begingroup
\edef\getnumargs@meaning{\meaning#1}%
\getnumargs@ifmacro
{%
\expandafter\getnumargs@settmp\expandafter{\getnumargs@meaning}%
\getnumargs@getnum
}%
\expandafter
\endgroup
\expandafter\def\expandafter#2\expandafter{\getnumargs@num}%
}
\newcommand\getnumargs@settmp[1]
{%
\expandafter\def\expandafter\getnumargs@tmp
\getnumargs@getargs#1\relax##1##2##3\relax{##2}%
}
\expandafter\def\expandafter\getnumargs@getargs
\expandafter#\expandafter1\detokenize{macro:}#2->#3\relax
{#2}
\edef\getnumargs@getnum
{%
\edef\noexpand\getnumargs@num
{%
\noexpand\the\noexpand\numexpr
\noexpand\getnumargs@tmp
\string#1\string#2\string#3%
\string#4\string#5\string#6%
\string#7\string#8\string#9%
.{10}\relax
-1\relax
}%
}
\makeatother
\newcommand\noargs{}
\newcommand\onearg [1]{}
\newcommand\twoargs [2]{}
\newcommand\threeargs[3]{}
\newcommand\fourargs [4]{}
\newcommand\fiveargs [5]{}
\newcommand\sixargs [6]{}
\newcommand\sevenargs[7]{}
\newcommand\eightargs[8]{}
\newcommand\nineargs [9]{}
\begin{document}
\getnumargs\section\tmp
\tmp
\getnumargs\texttt\tmp
\tmp
\getnumargs\emph\tmp
\tmp
\getnumargs\noargs\tmp
\tmp
\getnumargs\onearg\tmp
\tmp
\getnumargs\twoargs\tmp
\tmp
\getnumargs\threeargs\tmp
\tmp
\getnumargs\fourargs\tmp
\tmp
\getnumargs\fiveargs\tmp
\tmp
\getnumargs\sixargs\tmp
\tmp
\getnumargs\sevenargs\tmp
\tmp
\getnumargs\eightargs\tmp
\tmp
\getnumargs\nineargs\tmp
\tmp
\end{document}
\newcommand... One could build something with\meaning. – Skillmon Oct 07 '20 at 19:56#etc you really can't tell. Also typically you need the effective use eg you want to know\sectionis used with arguments even though\meaningwill tell you it has none. – David Carlisle Oct 07 '20 at 20:05\expandafter\def\expandafter\testA\expandafter#\expandafter1\string#2{#1/blabla}\typeout{\meaning\testA}\def\testB#1#2{#1/blabla}\typeout{\meaning\testB}\typeout{meanings \ifx\testA\testB are equal\else differ\fi}\stopHere the macros\testAand\testBdo exactly the same but are considered different:\catcode`\Y=6\relax\def\testA#1#2{}\def\testBY1Y2{}\typeout{\meaning\testA}\typeout{\meaning\testB}\typeout{meanings \ifx\testA\testB are equal\else differ\fi}\stop– Ulrich Diez Dec 23 '21 at 12:49\let\para=#\def\testA#1#2{arg1: #1 arg2: #2}\def\testB\para1\para2{arg1: \para1 arg2: \para2}\typeout{\testA{1}{2}}\typeout{\testB{1}{2}}\typeout{\meaning\testA}\typeout{\meaning\testB}\typeout{meanings \ifx\testA\testB are equal\else differ\fi}\stop– Ulrich Diez Dec 23 '21 at 13:03