如何在保持API简洁的前提下拼接编译期类字符串对象?
编译期拼接类字符串对象的扩展需求
我尝试在编译期拼接类字符串对象,实现了如下代码,但该实现仅支持字符串字面量和char数组,希望能扩展功能以支持其他编译期类字符串对象:
#include <cstddef> #include <utility> #include <algorithm> #include <array> #include <string_view> template <std::size_t N> class CharArray { private: std::array<char, N> _string; template <std::size_t S> friend class CharArray; template <std::size_t S1, std::size_t S2> constexpr CharArray(const std::array<char, S1> s1, const std::array<char, S2> s2) : _string() { std::copy(s1.begin(), s1.end() - 1, _string.begin()); std::copy(s2.begin(), s2.end() - 1, _string.begin() + S1 - 1); } public: constexpr CharArray(const char (&str)[N]) : _string() { std::copy(&str[0], &str[0] + N, _string.begin()); } constexpr CharArray(const std::array<char, N>& str) : _string() { std::copy(std::cbegin(str), std::cend(str), _string.begin()); } template <std::size_t S> constexpr auto operator+(const CharArray<S> other) const { return CharArray<N + other._string.size() - 1>(_string, other._string); } [[nodiscard]] constexpr auto c_str() const { return _string.data(); } }; template <std::size_t N, typename... Strings> constexpr auto join_chars(const char (&first)[N], Strings&&... rest) { if constexpr (!sizeof...(Strings)) { return CharArray<N>{first}; } else { return CharArray<N>{first} + join_chars(std::forward<Strings>(rest)...); } } #include <iostream> int main() { // 这段代码可以正常运行 constexpr const char name[] = "Edward"; constexpr auto joined1 = join_chars("name=", name); std::cout << joined1.c_str() << std::endl; // 这段代码无法运行 // constexpr std::string_view value = "42"; // 本质和constexpr const char*一致 // constexpr auto joined2 = join_chars("value=", value); // std::cout << joined2.c_str() << std::endl; return 0; }
编辑1:
根据建议,通过在CharArray类中添加以下两个静态函数实现了扩展:
template <std::size_t N> class CharArray { //... 原有代码 public: static constexpr CharArray create(const char* c_ptr) { std::array<char, N> tmp_array; std::copy(c_ptr, c_ptr + N, tmp_array.begin()); CharArray<N> char_array{tmp_array}; return char_array; } template <typename T> requires std::is_constructible_v<std::string_view, T> static constexpr CharArray create(const T& str) { return CharArray::create(str.data()); } };
再添加一个宏和重载函数:
template <typename T> requires std::is_constructible_v<std::string_view, T> constexpr std::size_t constexpr_strlen(const T& c_ptr) { return std::string_view{c_ptr}.length(); } #define ConstexprChars(str) CharArray<constexpr_strlen(str) + 1>::create(str) template <std::size_t N, typename... Strings> constexpr auto join_chars(const CharArray<N>& first, Strings&&... rest) { if constexpr (!sizeof...(Strings)) { return first; } else { return first + join_chars(std::forward<Strings>(rest)...); } }
之后可以这样调用:
int main() { constexpr const char* value = "42"; constexpr auto joined2 = join_chars("value=", ConstexprChars(value)); std::cout << joined2.c_str() << std::endl; return 0; }
但这种方式改变了原有API,我希望能在保持原API不变的前提下实现该功能,即直接使用如下调用方式:
int main() { constexpr const char* value = "42"; constexpr auto joined2 = join_chars("value=", value); std::cout << joined2.c_str() << std::endl; return 0; }
编辑2:
我找到一个相关视频,里面处理过类似问题(还添加了静态存储),使用了lambda作为constexpr函数参数的技巧(这是允许的)。不过视频里没有使用我这种CharArray类,且该技巧仍需用lambda包裹char*,并未简化API,所以我猜测目前这已是最优方案。
内容的提问来源于stack exchange,提问作者lobelk
相关产品推荐
相关产品推荐

