[TOC]
time: 2017/08/16
The problem
In the cpp2lua code, the source code uses the specialization of the function template, which results in the userData type when the specialization parameter is a string pointer (const char**), which is not the desired string type. In the case of Lua, calling a function that is not desired is a template specialization problem.
Part of the code is as follows:
// Definition 1: Template <typename T> Inline void PushToLua(lua_State *L, T data) {CppToLua<T>::ConvertUserdata(L, data); }; // Definition 2: Base template function (type pointer) Template <typename T> Inline void PushToLua(lua_State *L, T* data) {CppToLua<T>::ConvertUserdata(L, data); }; // Definition 3: Template <> inline void PushToLua(lua_State *L, const char* data) {lua_pushString (L, data); } // lua code with PushToLua<R>(L, result);Copy the code
Results:
Print (test:GetStr()) // Print the result, I want GetStr return string, such as :"test" userData: 00921DD8Copy the code
The base template function was called instead of the specialized one I wanted
Definition 3 Inline void PushToLua(lua_State *L, const char* data) Definition 1 Inline void PushToLua(lua_State *L, T data)Copy the code
To reassure
Basic knowledge of
Let’s start with the basics
- The full specialization of a function template can be written in two ways [2]
template < >
int compare<const char*>(const char* left, const char* right)
{
std::cout <<"in special template< >..." <<std::endl;
return strcmp(left, right);
}
Copy the code
Can also be
template < >
int compare(const char* left, const char* right)
{
std::cout <<"in special template< >..." <<std::endl;
return strcmp(left, right);
}
Copy the code
- Overloading and specialization
(1) Function templates only have full specialization, but no partial specialization. It can be understood that overloading can solve the requirement of partial specialization;
Template
; template
;
(3) The specialized version of the function template is an empty argument type: template<>.
- Function call rules:
(1) Give priority to non-template functions;
(2) If there are no non-template functions, find the basic template first;
(3) After determining the base template, check whether there is a specialized version of the base template.
- summary
From the above function call rules, we can see why definition 1 was called instead of definition 3
(1) Definition 1 and definition 2 are two base templates, so they are preferred (because there are no non-template functions);
(2) A specialized version is a specialized version of one of the base templates;
(3) During debugging, it was determined as follows: when the function was called again, the basic template of definition 1 was selected to call. Definition 3 is a specialized version of definition 2, not definition 1.
(4) Then another question arises: why is the base template for definition 1 called instead of the base template for definition 2?
Another question
- test
If I remove the used convention parameter type, modify it as follows:
// use PushToLua(L, result);Copy the code
At this point, it is possible to find specialized templates
template<>
inline void PushToLua(lua_State *L, const char* data) {
lua_pushstring(L, data);
}
Copy the code
That is, the output is a string, not userData.
The same is true if you add a non-template function:
inline void PushToLua(lua_State *L, const char* data) {
lua_pushstring(L, data);
}
Copy the code
The result is:
(1)PushToLua (L, result); The call method does not execute to this function, but to the base template class for value passing (non-pointer passing for definition 1);
(2) if PushToLua(L, result); Call method, which takes precedence over non-template functions.
- guess
(1) If PushToLua<R\*>(L, result) specifies the base template for definition 1, if PushToLua<R\*>(L, result) specifies the base template for definition 2;
(2)PushToLua(L, result) is called in accordance with the above rules, i.e. R is passed as a const char*, which matches the base template of definition 2.
(3) This can be seen from calls to int, even with PushToLua(L, member); Calling a version of an integer results in an integer, not a userData.
To solve
- 1. Add a non-template function whose argument is a string pointer type
Inline void PushToLua(lua_State *L, const char* data) {lua_pushString (L, data); // Definition 4: Inline void PushToLua(lua_State *L, const char* data) {lua_pushString (L, data); }Copy the code
- 2. Change the usage mode to the following:
// PushToLua<R>(L, result); // PushToLua(L, result);Copy the code
conclusion
- Remember the calling rules of function templates and beware of pitfalls
- PushToLua is used in a special way, so it is best to use it in the same way as normal function calls.
- The conjecture part has not been studied and confirmed
reference
[1] Why not specialize function templates? [2] C++ template specialization in detail (function template specialization, class template specialization)