Differences in the compiler's implementation of the function pack extension for C + + 11 parameter templates (Variadic template)
The topic is quite round the mouth. C + + 11 is not too much of a good thing, but the Variadic template is certainly one of the dazzling stars, in C + + design new thinking, you can see a lot of template code in order to support the number of indeterminate parameters, but to overload 1 parameters to n template parameters n functions. Although the type of code is generally used to use the macro and footstep assist generation. But I don't think anyone would like to see thousands of rows of this monotonous function. Through this stuff, the power of the template can erupt.
The current compiler has basically supported the variadic template, and both GCC 4.6 and Visual Studio 2013 already support the variable parameter template. But today, when I was writing a LUA bonding layer, I found an interesting question.
First, the code.
1#include <iostream>2 3 4Template <typename ... T>5 voidDummy_wrapper (t ... t)6 {7 };8 9Template <classT>TenT Unpacker (ConstT T) One { AStd::cout <<'['<< T <<']'; - returnT; - } the - -Template <typename ... Args> - voidWrite_line (Constargs&.. data) + { - Dummy_wrapper (unpacker (data) ...); +Std::cout <<'\ n'; A } at - intMain () - { -Write_line (1,"--","2.2.2","--",3.0); - return 0; -}
As a little explanation, Write_line is a template function that accepts a parameter, and internally calls Dummy_wrapper, which assists in package expansion, allowing each parameter to invoke the Unpacker (data) function. What is the expected output of this code?
I think most people would think [1][--][2.2.2][--][3], but in fact the output on Visual C + + 2013 and GCC 4.8 is exactly the opposite. The output is [3][--][2.2.2][--][1]. Is it a bit of a mess?
I think the reason for this problem is because C + + parameters in the stack order is from right to left, 1 This parameter is calculated after processing, was first thrown into the stack. Instead, it becomes the right-most parameter. So that's what caused the problem.
In fact, frankly speaking, this kind of problem is a problem that is not stated in typical norms. In fact, I think from the results and semantic correctness, [1][--][2.2.2][--][3] output is certainly more correct, but this for the compiler, it is necessary to wait for a number of results calculated, and then into the stack.
And this issue in the IBM compiler team's written "in-depth understanding of c++11" also mentioned that the IBM compiler XL compiler similar test output is sequential, they also tested GCC, they think the GCC output is chaotic (in fact, in reverse).
How to avoid this problem? One way to do this is to pass the arguments back to the Write_line function, but this method is not portable (who knows which day the bug will be fixed, and what can you do when you output something?). )。
In fact, you can consider using recursive package extension methods,
1#include <iostream>2 3Template <typename ... Tlist>4 voiddummy_wrapper (Tlist ... tlst)5 {6 };7 8Template <typename T, TypeName ... Tlist>9 voidDummy_wrapper (t T, Tlist ... tlst)Ten { One Unpacker (t); A dummy_wrapper (Tlst ...); - }; - theTemplate <classT> -T Unpacker (ConstT T) - { -Std::cout <<'['<< T <<']'; + returnT; - } + ATemplate <typename ... Args> at voidWrite_line (Constargs&.. data) - { - dummy_wrapper (data ...); -Std::cout <<'\ n'; - } - in intMain () - { toWrite_line (1,"--","2.2.2","--",3.0); + return 0; -}
When this is rewritten, the output becomes [1][--][2.2.2][--][3],
This way the parameters are expanded, so the above problems are avoided. Most of the situation can be rewritten to circumvent part of the problem. But of course it doesn't solve all the problems,
One of the middle of my code is this, to register a function with Lua,
1template<TypeName Ret_type,2TypeName ...args_type>3 classG_functor_ret4 {5 Public:6 Static intInvoke (Lua_state *State )7 {8 void*upvalue_1 = Lua_touserdata (state, Lua_upvalueindex (1));9Ret_type (*fun_ptr) (Args_type ...) = (Ret_type (*) (Args_type ...)) (upvalue_1);Ten intPara_idx =0; OnePush_stack<ret_type> (State, Fun_ptr (read_stack<args_type> (state, para_idx++)...)); A } -};
Fun_ptr (read_stack<args_type> (state, para_idx--) ...) This code, because Fun_ptr is a function pointer, I can not write a recursive method for all function pointers, so the above method is invalid.
What do we do? Can only first put the parameters in reverse, and later, such as the compiler update and then slowly change, and only this very frustrated method to deal with first. Currently I can test the VS2013 and GCC 4.8 is still a problem.
"This is the author is the Wild Goose Watanabe, in the spirit of freedom, you can in the absence of profit in the full reprint of this document, reproduced when please attach blog link: http://blog.csdn.com/fullsail/, otherwise each word a dollar, each figure 100 does not bargain. Baidu Library and 360doc increase by one times "
Differences in the compiler's implementation of the function pack extension for C + + 11 parameter templates (Variadic template)