Introduction
There are many cases when we need to determine if a string
is literal. For example, one of such cases is logging optimization without formatting parameters in the worker thread. The most of logging parameters are string
literals of the "text to log out" form. So, there is no need to use resources for copying such literals, because they can be transmitted as a pointer. However, it is necessary to define, how exactly the string
is specified, and is it a string
at all. What is more, we should define it in compile-time.
The method described below will do this. Code can be used both for char
and wchar_t
.
Strategy
In order to determine the type of parameter, we need to:
- define if the parameter (without cv-qualifiers) is of types
char
or wchar_t
- define if the parameter is an
array
- compare the value of the parameter with
string #x (or L#x)
, preprocessed from this
parameter, character-by-character
static constexpr bool value(const __Char(&str1)[N], const __T& str2)
{
return
sizeof (str1) > sizeof(str2) &&
_decay_equiv<__T, const __Char*>::value &&
_is_array(str2) &&
_is_same<decltype(str1), __T,
(sizeof(str2) / sizeof(__Char)) - 2>::value(str1, str2, _move_sz<__Char>::val);
}
static constexpr bool value(const __Char(&str1)[N], const char*& str2)
{
return false;
}
static constexpr bool value(const __Char(&str1)[N], const wchar_t*& str2)
{
return false;
}
The above str1
is a string
, preprocessed from the parameter under consideration, str2
-
the parameter itself.
By Steps
- Use the structure below to compare the parameter type without cv-qualifiers:
template <typename T, typename U> struct _decay_equiv :
std::is_same<typename std::decay<T>::type, U>::type {
};
- Define if the parameter is an array of characters:
template<uint32_t __Sz> static constexpr bool _is_array(const __Char(&d)[__Sz]) {
return true;
}
static constexpr bool _is_array(...) {
return false;
}
- Compare with preprocessed
string #x
or L#x
.
If argument is literal string
, it will look like "\"text\""
or "L\"text\""
and will contain characters 'L'
and '\"'
. The length of the preprocessed string
will always be greater than the length of the string
parameter (because rest of the cases are filtered by the conditions above). So, comparing string
parameter with preprocessed string
character-by-character, it is necessary to shift index of character, that is compared, by '\"'
(for char) or by '\"'
and 'L'
(for wchar_t
).
template<typename __Ch> struct _move_sz {
enum { val = 0 };
};
template<> struct _move_sz<char> {
enum { val = 1 }; };
template<> struct _move_sz<wchar_t> {
enum { val = 2 }; };
Compare as recursion:
template<typename __Type1, typename __Type2, int32_t __Ix> struct _is_same {
static constexpr bool value(const __Type1& str1, const __Type2& str2, int32_t move) {
return (str1[__Ix + move] == str2[__Ix]) &&
(_is_same<__Type1, __Type2, __Ix - 1>::value(str1, str2, move));
}
};
template<typename __Type1, typename __Type2> struct _is_same<__Type1, __Type2, 0> {
static constexpr bool value(const __Type1& str1, const __Type2& str2, int32_t move) {
return (str1[move] == str2[0]);
}
};
The above str1
is the preprocessed string, str2
- the parameter under consideration,
move
- used offset.
In the End
It is convenient to define the call as:
#define is_literal_string_a(x) is_literal_string<sizeof(#x) / sizeof(char),
decltype(x), char>::value(#x, x)
#define is_literal_string_w(x) is_literal_string<sizeof(L#x) / sizeof(wchar_t),
decltype(x), wchar_t>::value(L#x, x)
Conclusion
The code below can be used for testing:
int main()
{
const char* h1 = "test_1";
const wchar_t* h3 = L"test_3";
const wchar_t h4[] = { L'g', L'g', L'g', L'g' };
enum {
v1 = is_literal_string_a(h1),
v2 = is_literal_string_a("test_4"),
v3 = is_literal_string_w(h3),
v4 = is_literal_string_w(L"test_5"),
v5 = is_literal_string_w(10),
v6 = is_literal_string_w(h4),
};
printf("v1 = %d\n", v1);
printf("v2 = %d\n", v2);
printf("v3 = %d\n", v3);
printf("v4 = %d\n", v4);
printf("v5 = %d\n", v5);
printf("v6 = %d\n", v6);
return 0;
}
The code was tested in Visual Studio 2015.
Have a nice code!