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?
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.
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)
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With