quant
quant

Reputation: 23042

How do I find the number of template arguments used to declare a class?

How can I retrieve the number of template arguments that were used to construct some class? To clarify what I'm after, let's say I have some class instance, A a;, and I run the following to get its name:

boost::units::detail::demangle(typeid(decltype(a)).name())

Let's say the output of this call is someNamespace::A<Arg1<A,B>,int,5,Arg2<C,D>>. I want to find a way of reliably getting the number of arguments (ie. 4), considering that the arguments themselves might have any number of levels of nested template arguments themselves (which I don't want to count - ie. I want to count Arg1<A,B> as a single argument), and that the arguments could be any mix of types and values.

I'm open to manual string-wrestling to get this done but my preference is a compact solution using boost/STL.

Any ideas?

Upvotes: 4

Views: 101

Answers (1)

John Zwinck
John Zwinck

Reputation: 249123

Let's take the string in your example (with whitespace for clarity):

someNamespace::A< Arg1<A,B>, int, 5, Arg2<C,D> >

You want to get "4" from this, because there are four top-level types in the template. The most robust way is to think about it as a grammar. We could use Boost Spirit (warning: very hard to get right, and deity help you if you have a compiler error). We could use ANTLR or good old flex/bison to generate a parser for the little language. If we did that we'd aim to generate an AST containing the four type children together as siblings (two of them containing their own children and ).

But maybe a hand-written parser is easier. From left to right you can keep a counter of how many angle-brackets you're inside of:

someNamespace::A< Arg1<A,B>, int, 5, Arg2<C,D> >
000000000000000011111122221111111111111112222110

Then it's just a matter of counting commas when the bracket count is 1:

someNamespace::A< Arg1<A,B>, int, 5, Arg2<C,D> >
000000000000000011111122221111111111111112222110
                           1    2  3

Of course you add one for the initial type.

Upvotes: 1

Related Questions