[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)