Reputation: 3989
While writing code for wrapping Lua, I came across the need for passing string literals and started to wonder which way it is the most efficient.
I have the choice between two functions:
void lua_pushstring (lua_State* L, const char* str);
void lua_pushlstring(lua_State* L, const char* str, size_t len);
Of course, the 1st function uses strlen()
internally, the 2nd one is thus faster.
Now, if it's known at compile time, I'd like to avoid calculating string length, as laid out here and here:
// Overload 1
template <size_t N>
inline void pushstring(lua_State* L, const char (&str) [N])
{
lua_pushlstring(L, str, N-1);
}
As nice as this function works when called with a string literal: pushstring(L, "test");
of course it doesn't compile when called with a const char*
, for example in a longer function which is in a .cpp
file:
// this is in a .cpp file
void long_function(lua_State* L, const char* str)
{
// do lots of stuff
pushstring(L, str); // compile error
// do more stuff
}
Now if I add
// Overload 2
inline void pushstring(lua_State* L, const char* str)
{
lua_pushstring(L, str);
}
it is for some reason (C++ overload resolution is tricky) preferred over Overload 1
, which is thus never called.
Is there a clever way to fix that?
Upvotes: 4
Views: 2310
Reputation: 171303
If you declare both with the second one forwarding to the first:
void lua_pushlstring(lua_State* L, const char* str, size_t len);
inline void lua_pushstring (lua_State* L, const char* str)
{ lua_pushlstring(L, str, strlen(str)); }
Then a decent compiler will optimise away the strlen
call when you call the second function with a literal, e.g. it will inline
lua_pushstring(L, "hello");
and because strlen
on a literal can be optimised to a constant, it will replace it with a call to:
lua_pushlstring(L, "hello", 5);
That gives you the simple syntax of calling the two-argument form, without paying for strlen
on literals.
When the length is already known it can be passed:
lua_pushlstring(L, s.c_str(), s.length());
Or this works too, but with an unnecessary call to strlen
lua_pushstring(L, s.c_str());
Upvotes: 4
Reputation: 208353
I would offer two options:
void f( const char*, int );
template <int N> void f( const char (&str)[N] ) {
f( str, N-1 );
}
(or rather std::size_t
), Now users that have a string literal can call the second that will internally dispatch to the first. Users that don't have a literal but a const char*
are responsible for providing the correct size.
Upvotes: 5
Reputation: 9547
To elaborate further on your template version:
#include <iostream>
template <typename T>
inline void pushstring(T str);
template <int N>
inline void pushstring(const char (&str) [N])
{
std::cout << N << std::endl;
}
template <>
inline void pushstring(const char *str)
{
std::cout << str << std::endl;
}
See a test run here:
Wrong parameter -> linker error: http://ideone.com/vZbj6
Rigt parameter -> runs great :) : http://ideone.com/iJBAo
Upvotes: 2