Other than tables or full userdata (which have per-value metatables), what do you need? I’m unclear on what use a metatable on a particular string, or a light userdata would have (why would it not be a full userdata in that case?).
lightuserdata can be a sub struct of an complex C/C++ object .
For example, in 3d engine, a node of a 3d object as a lightuserdata would be better than full userdata. If you query a node of a 3d object from lua , you can create a full userdata proxy for it, but you should also cache it in uservalue because it should be the same value in next query ( __eq is not enough if you want to use it as a table key).
Using lightuserdata (with metatable) for a 3d node would simplify the bindings of 3d engine and reduce the overhead.
But a light userdata with a metatable basically *IS* a full userdata. The only difference is that the full userdata is allocated by Lua, and undergoes garbage collection .. which you ALSO want for the __gc. As you noted, the technique here is to allocate a full userdata that just holds a C pointer (aka a light userdata).
Your request won’t get you a lower overhead .. it will just get you something else that is identical to full userdata but with a different name.