Qt 与 constexpr 字符串文字
Qt vs constexpr string literal
有没有办法在Qt中定义为静态constexpr字符串文字成员? IE。类似于以下内容:
class X
{
static constexpr QString tag = "mytag";
};
考虑到 QString
是一个(可能)heap-allocated 字符串,并且您不能在 constexpr
代码中分配内存,不。它在 compile-time 并不比使用 std::string
.
更有效
我做了 Jesper 在他的评论中推荐的,我使用了 QLatin1String。但是我通过一个小助手 class 使用它来避免 QLatin1String:
中的 strlen() 调用
struct ConstLatin1String : public QLatin1String
{
constexpr ConstLatin1String(const char* const s) :
QLatin1String(s, static_cast<int>(std::char_traits<char>::length(s))) {}
};
这允许做:
static constexpr ConstLatin1String mystring = "foo";
受 启发,但适用于 c++11
#include <QLatin1String>
namespace detail {
// Helper function for getting compile-time string literal's length
// Given from:
// c++11 analogue of: std::char_traits<char>::length(str); from c++14
constexpr std::size_t constLength(const char* str)
{
return ((*str) == '[=10=]') ? 0 : constLength(str + 1) + 1;
}
} // namespace detail
// Constructs compile-time <QLatin1String> from string literal
constexpr QLatin1String make_string(const char* str)
{
return QLatin1String(str, detail::constLength(str));
}
// Alternate implementation for string literals only, without
// recursive function call (reduces compilation time), using
// known in compile-time size.
template <std::size_t SIZE>
constexpr QLatin1String make_string_from_literal(const char (&str)[SIZE])
{
return QLatin1String(str, SIZE);
}
// Example of usage:
static constexpr QLatin1String STR = make_string("hello_world");
测试
// Helper function for compile-time strings comparison
// Given from
constexpr bool strings_equal(const char* a, const char* b) {
return (*a == *b) && (*a == '[=11=]' || strings_equal(a + 1, b + 1));
}
// Compile-time in-place construction check
static_assert( strings_equal(make_string("foo").data(), "foo"), "test failed");
// Compile-time constant construction check
static constexpr QLatin1String STR = make_string("bar");
static_assert( strings_equal(STR.data(), "bar"), "test failed");
补充灵感
它与 compile-time hashing
完美搭配,例如 in that brilliant answer, which based on (that and that)
// Note: `len` must be without null-character sign
constexpr uint32_t crc32(const char* str, std::size_t len) {
return detail::crc32(len - 1, str) ^ 0xFFFFFFFF;
}
template <std::size_t LEN>
constexpr std::uint32_t crc32(const char (&str)[LEN]) {
return crc32(str, LEN - 1);
}
// Overload for <QLatin1String>
// Notice that, next methods: QLatin1String::{.data(), .size()}
// marked as constexpr only since Qt 5.6.
constexpr std::uint32_t crc32(const QLatin1String& str) {
return crc32(str.data(), str.size());
}
// ------------------------------------------------------------
// Test with explicitely specified literal size
static_assert( crc32("hello world", 11) == 0xd4a1185, "CRC32 test failed");
static_assert( crc32("foo bar", 7) == 0xbe460134, "CRC32 test failed");
// Test with implicitly calculated literal size
static_assert( crc32("hello world") == 0xd4a1185, "CRC32 test failed");
static_assert( crc32("foo bar") == 0xbe460134, "CRC32 test failed");
// Test with convenient overload for <QLatin1String>
static constexpr QLatin1String STR_1 = make_string("hello world");
static constexpr QLatin1String STR_2 = make_string("foo bar");
static_assert( crc32(STR_1) == 0xd4a1185, "CRC32 test failed");
static_assert( crc32(STR_2) == 0xbe460134, "CRC32 test failed");
允许通过 switch-case 进行 compile-time 字符串匹配。
两种 switch
情况都相等并在 compile-time 中计算:)
-
- 在 compile-time 中构造的字符串,允许在任何情况下使用它,并在需要的地方计算散列。
-
- pre-computed 来自字符串的哈希值。字符串不存在。
-
- 就地使用没有任何仪式:D
static constexpr QLatin1String MATCH_1 = make_string("value_1"); // 1)
static constexpr auto MATCH_2 = crc32( make_string("value_2") ); // 2)
const QLatin1String str = /* ... */;
switch( crc32(str) )
{
case crc32(MATCH_1): { do_something_for_value_1(); } break; // 1)
case MATCH_2: { do_something_for_value_2(); } break; // 2)
case crc32("value_3"): { do_something_for_value_3(); } break; // 3)
}
有没有办法在Qt中定义为静态constexpr字符串文字成员? IE。类似于以下内容:
class X
{
static constexpr QString tag = "mytag";
};
考虑到 QString
是一个(可能)heap-allocated 字符串,并且您不能在 constexpr
代码中分配内存,不。它在 compile-time 并不比使用 std::string
.
我做了 Jesper 在他的评论中推荐的,我使用了 QLatin1String。但是我通过一个小助手 class 使用它来避免 QLatin1String:
中的 strlen() 调用struct ConstLatin1String : public QLatin1String
{
constexpr ConstLatin1String(const char* const s) :
QLatin1String(s, static_cast<int>(std::char_traits<char>::length(s))) {}
};
这允许做:
static constexpr ConstLatin1String mystring = "foo";
受 c++11
#include <QLatin1String>
namespace detail {
// Helper function for getting compile-time string literal's length
// Given from:
// c++11 analogue of: std::char_traits<char>::length(str); from c++14
constexpr std::size_t constLength(const char* str)
{
return ((*str) == '[=10=]') ? 0 : constLength(str + 1) + 1;
}
} // namespace detail
// Constructs compile-time <QLatin1String> from string literal
constexpr QLatin1String make_string(const char* str)
{
return QLatin1String(str, detail::constLength(str));
}
// Alternate implementation for string literals only, without
// recursive function call (reduces compilation time), using
// known in compile-time size.
template <std::size_t SIZE>
constexpr QLatin1String make_string_from_literal(const char (&str)[SIZE])
{
return QLatin1String(str, SIZE);
}
// Example of usage:
static constexpr QLatin1String STR = make_string("hello_world");
测试
// Helper function for compile-time strings comparison
// Given from
constexpr bool strings_equal(const char* a, const char* b) {
return (*a == *b) && (*a == '[=11=]' || strings_equal(a + 1, b + 1));
}
// Compile-time in-place construction check
static_assert( strings_equal(make_string("foo").data(), "foo"), "test failed");
// Compile-time constant construction check
static constexpr QLatin1String STR = make_string("bar");
static_assert( strings_equal(STR.data(), "bar"), "test failed");
补充灵感
它与 compile-time hashing
完美搭配,例如 in that brilliant answer, which based on (that and that)
// Note: `len` must be without null-character sign
constexpr uint32_t crc32(const char* str, std::size_t len) {
return detail::crc32(len - 1, str) ^ 0xFFFFFFFF;
}
template <std::size_t LEN>
constexpr std::uint32_t crc32(const char (&str)[LEN]) {
return crc32(str, LEN - 1);
}
// Overload for <QLatin1String>
// Notice that, next methods: QLatin1String::{.data(), .size()}
// marked as constexpr only since Qt 5.6.
constexpr std::uint32_t crc32(const QLatin1String& str) {
return crc32(str.data(), str.size());
}
// ------------------------------------------------------------
// Test with explicitely specified literal size
static_assert( crc32("hello world", 11) == 0xd4a1185, "CRC32 test failed");
static_assert( crc32("foo bar", 7) == 0xbe460134, "CRC32 test failed");
// Test with implicitly calculated literal size
static_assert( crc32("hello world") == 0xd4a1185, "CRC32 test failed");
static_assert( crc32("foo bar") == 0xbe460134, "CRC32 test failed");
// Test with convenient overload for <QLatin1String>
static constexpr QLatin1String STR_1 = make_string("hello world");
static constexpr QLatin1String STR_2 = make_string("foo bar");
static_assert( crc32(STR_1) == 0xd4a1185, "CRC32 test failed");
static_assert( crc32(STR_2) == 0xbe460134, "CRC32 test failed");
允许通过 switch-case 进行 compile-time 字符串匹配。
两种 switch
情况都相等并在 compile-time 中计算:)
-
- 在 compile-time 中构造的字符串,允许在任何情况下使用它,并在需要的地方计算散列。
-
- pre-computed 来自字符串的哈希值。字符串不存在。
-
- 就地使用没有任何仪式:D
static constexpr QLatin1String MATCH_1 = make_string("value_1"); // 1)
static constexpr auto MATCH_2 = crc32( make_string("value_2") ); // 2)
const QLatin1String str = /* ... */;
switch( crc32(str) )
{
case crc32(MATCH_1): { do_something_for_value_1(); } break; // 1)
case MATCH_2: { do_something_for_value_2(); } break; // 2)
case crc32("value_3"): { do_something_for_value_3(); } break; // 3)
}