Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

do recursive templates producing runtime code?

consider the following class:

class test {

  // recursively template 
  template<typename T, typename... R>
  void add(T t, R... r) {
    // do something with t
    if(sizeof...(r))
      add(r...);
  }
  // since the variadic template add is recursive, there have to be an end.
  void add() {}

public:

  template<typename... T>
  explicit test(T... rest) {
    add(rest...);
  }
};

and the following main:

int main() {
  test t1(1);
  test t2(1, 2);
  test t3(1, 2, 3);
}

i shrunk down the code, so the add methods may not necessary.

i think this code is not generating runtime recursion code, but creates 3 different constructors with 3 different number of parameters. am i right? i just want to make sure if i am right or not. if not what will happen then?

edit:

the answers from bames53 and Casio Neri are exact what i expected what is happening. however, it is not recursive but it still calling the the seperate add's like it would be one as you can see in bames53 answer. it's like semi-recursion.

like image 473
user1810087 Avatar asked Jun 01 '26 07:06

user1810087


2 Answers

All code in templates is generated at compile time. That is the entire point of templates, variadic templates are no different, generally you do compile time recursion to get variadic templates to terminate. It is basically as if you had written the methods as nested. After the phase of the compiler where templates are expanded (not sure if this is exactly how it works, I'm not a compiler expert) it basically looks as if there had never been templates they are expanded out and turn into template instances, which are in essence no different than normal code. I would guess that generally the compiler will also inline most of the methods generated by variadic templates to produce more efficient code.

EDIT: keep in mind when I wrote this I decided to give you some credit and assume that your actual code does more than what you posted (which essentially does nothing)

like image 58
aaronman Avatar answered Jun 02 '26 20:06

aaronman


Yes, in your case the compiler will generate 3 overloads of test::add and 3 overloads of test::test (taking 1, 2 and 3 arguments of type int).

To check that, compile the code (in file main.cpp) with gcc using options -std=c++11 -c main.cpp. This generates main.o. Then use nm -C main.o to check the symbols in the object file. You'll get (among other things)

00000000 T void test::add<int>(int)
00000000 T void test::add<int, int>(int, int)
00000000 T void test::add<int, int, int>(int, int, int)
00000000 T test::test<int>(int)
00000000 T test::test<int, int>(int, int)
00000000 T test::test<int, int, int>(int, int, int)

Where you can see all the mentioned overloads.

It's worth mentionning that gcc didn't create code for test::add that takes no argument (the non-template function) because it inlines the call. If you move the definition out of the class:

void test::add() {}

then gcc also generates this symbol and the output of nm -C main.o includes

00000000 T test::add()
like image 20
Cassio Neri Avatar answered Jun 02 '26 19:06

Cassio Neri