Differences between the compiler's function package extension implementation for the variable parameter Template (Variadic Template) in C ++ 11, variadictemplate
Differences between the compiler's function package extension implementation for the C ++ 11 Variable Parameter Template (Variadic Template)
The question is quite difficult. There are not many good things in C ++ 11, but Variadic Template must be one of the dazzling stars. In the new thinking of C ++ design, you can see that many template codes need to overload one parameter to N functions of N template parameters to support the uncertain number of parameters. Although the Code is generally generated with macros and footsteps. But I don't think anyone would like to see thousands of monotonous functions. With this stuff, the power of the template can erupt.
Currently, the latest compilers support Variadic Template, and GCC 4.6 and Visual studio 2013 support Variable Parameter templates. But today I found an interesting problem when writing a Lua bonding layer.
Run the code first.
1 #include <iostream> 2 3 4 template <typename ... T> 5 void dummy_wrapper(T... t) 6 { 7 }; 8 9 template <class T>10 T unpacker(const T t)11 {12 std::cout << '[' << t << ']';13 return t;14 }15 16 17 template <typename... Args>18 void write_line(const Args& ... data)19 {20 dummy_wrapper(unpacker(data)...);21 std::cout << '\n';22 }23 24 int main()25 {26 write_line(1, "--", "2.2.2", "--", 3.0);27 return 0;28 }
As explained in a bit, write_line is a template function that accepts variable parameters. It calls dummy_wrapper internally. This function helps the main worker to perform package expansion and allows each parameter to call the unpacker (data) function. So what is the expected output of this code?
I think most people will think that [1] [--] [2.2.2] [--] [3], however, the output on Visual C ++ 2013 and GCC 4.8 is the opposite. The output is [3] [--] [2.2.2] [--] [1]. Is it a bit difficult?
I think the reason for this problem is that the input sequence of the C ++ parameter is from right to left. After the parameter 1 is calculated and processed, it is first thrown into the stack. Instead, it becomes the rightmost parameter. This problem is caused.
In fact, frankly speaking, this is a problem that the typical norms do not specify. In fact, in terms of result and semantic correctness, the output of [1] [--] [2.2.2] [--] [3] is certainly more correct, but for the compiler, it is necessary to wait for several results to be calculated and re-enter the stack.
This issue is also mentioned in the section "deep understanding of C ++ 11" written by the IBM compiler team. Similar test output results on the IBM compiler XL compiler are sequential, they also tested GCC, and they thought GCC output was messy (in descending order ).
How can we avoid this problem? There is a way to pass the Parameter Back To The write_line function, but this method is not portable (who knows which day the bug will be fixed, in addition, when you output something, can you think about the problem ?).
In fact, we can consider using recursive package extension methods,
1 #include <iostream> 2 3 template <typename ... Tlist> 4 void dummy_wrapper(Tlist... tlst) 5 { 6 }; 7 8 template <typename T, typename ... Tlist> 9 void dummy_wrapper(T t, Tlist... tlst)10 {11 unpacker(t);12 dummy_wrapper(tlst...);13 };14 15 template <class T>16 T unpacker(const T t)17 {18 std::cout << '[' << t << ']';19 return t;20 }21 22 template <typename... Args>23 void write_line(const Args& ... data)24 {25 dummy_wrapper(data...);26 std::cout << '\n';27 }28 29 int main()30 {31 write_line(1, "--", "2.2.2", "--", 3.0);32 return 0;33 }
After this rewrite, the output is [1] [--] [2.2.2] [--] [3],
In this way, parameters are expanded one by one, so the above problems are avoided. In most cases, you can rewrite it to avoid some problems. But of course this cannot solve all the problems,
In my code, there is a section in the middle to register a function to lua,
1 template<typename ret_type, 2 typename ...args_type> 3 class g_functor_ret 4 { 5 public: 6 static int invoke(lua_State *state) 7 { 8 void *upvalue_1 = lua_touserdata(state, lua_upvalueindex(1)); 9 ret_type(*fun_ptr)(args_type...) = (ret_type( *)(args_type...))(upvalue_1);10 int para_idx = 0;11 push_stack<ret_type>(state, fun_ptr(read_stack<args_type>(state, para_idx++)...));12 }13 };
Fun_ptr (read_stack <args_type> (state, para_idx --)...) in this Code, since fun_ptr is a function pointer, I cannot write a recursive method for all function pointers, so the above method is invalid.
What should we do? The parameter can only be passed in the reverse direction first, and the compiler will be updated later, and then it will be changed slowly, and only the method that is very frustrating will be handled first. Currently, problems still exist in VS2013 and GCC 4.8 That I can test.
[The author of this article is Yandu hantan. In the spirit of freedom, you can repost this document in full without profit. for reprinting, please attach the BLOG link: http://blog.csdn.com/fullsail/. if not, it is a dollar. Double the bidu library and 360doc price]