c++ 20 项目中优化 const 字符串文字的使用,以增强编译和运行时性能
在许多源文件中,字符串文字都是用 const std::string
声明的,如下例所示(定义了数十个字符串文字,然后连接起来形成新的字符串文字):
之前
// Example
namespace {
const std::string kPluginApi("plugins-api");
const std::string kGlobal(".global");
const std::string kInternal(".internal");
}
namespace {
const std::string kGLobalApiPlugin = kPluginApi + kGlobal;
const std::string kInternalApiPlugin = kPluginApi + kInternal;
}
问题是 std::string
通常在运行时初始化,尽管有 const 限定符。由于
std::string
通常涉及动态内存分配,因此运行时初始化,我想到使用
constexpr const char *
来确保尽可能编译时初始化,如下所示:
之后
namespace {
constexpr const char * kPluginApi = "plugins-api";
constexpr const char * kGlobal = ".global";
constexpr const char * kInternal = ".internal";
}
namespace {
const std::string kGLobalApiPlugin = std::string(kPluginApi) + kGlobal;
const std::string kInternalApiPlugin = std::string(kPluginApi) + kInternal;
}
std::string
的转换。
#include <array>
#include <string_view>
namespace ce
{
template <typename input_iterator_t, typename output_iterator_t>
constexpr void ce_copy(input_iterator_t first, input_iterator_t last, output_iterator_t to)
{
for(auto it = first; it != last; ++it, ++to)
{
*to = *it;
}
}
template <std::size_t N>
class string final
{
public:
constexpr string() = default;
constexpr string(const char (&str)[N]) noexcept
{
ce_copy(str, str + N, m_str.begin());
}
constexpr string(const string&) = default;
//explicit conversion to string_view
constexpr std::string_view sv() const noexcept
{
return std::string_view{ c_str(), N - 1 };
}
// implicit conversion to string_view
constexpr operator std::string_view() const noexcept
{
return std::string_view{ c_str(), N - 1 };
}
constexpr const char* c_str() const noexcept
{
return m_str.data();
}
constexpr char* str() noexcept
{
return m_str.data();
}
constexpr auto cbegin() const noexcept
{
return m_str.cbegin();
}
constexpr auto cend() const noexcept
{
return m_str.cend();
}
constexpr bool operator==(const char* rhs) const noexcept
{
return sv() == std::string_view{ rhs };
}
template <std::size_t M>
constexpr auto concat(const string<M>& rhs) const noexcept
{
string<N + M - 1> result;
ce_copy(cbegin(), cend(), result.str());
ce_copy(rhs.cbegin(), rhs.cend(), result.str() + N - 1);
return result;
}
constexpr auto operator[](const std::size_t index) const noexcept
{
return m_str[index];
}
constexpr auto& operator[](const std::size_t index) noexcept
{
return m_str[index];
}
private:
std::array<char, N> m_str{};
};
} //namespace ce
static constexpr ce::string kGlobal{ ".global" };
static constexpr ce::string kInternal(".internal");
static constexpr ce::string kPluginApi("plugins-api");
static constexpr ce::string kGLobalApiPlugin = kPluginApi.concat(kGlobal);
static constexpr ce::string kLocalApiPlugin = kPluginApi.concat(kInternal);
int main()
{
static_assert(kGLobalApiPlugin == "plugins-api.global");
}