C++编译期拼接可变数量字符串字面量用于static_assert实现问题
报错原因说明
你遇到的两个报错都是C++标准的明确限制:
- 字符串字面量的地址无法作为模板非类型参数:标准规定字符串字面量的地址不具备常量表达式的唯一性要求,不同编译单元的相同字面量可能有不同地址,因此不允许用于模板参数。
- 完美转发的入参如果没有显式声明为
constexpr,无法在常量表达式上下文使用,因此会提示参数不是常量表达式。
实现方案(C++20及以上)
通过封装字面量类类型作为编译期字符串载体,绕过字符串地址作为模板参数的限制,所有拼接逻辑完全在constexpr上下文执行,无需依赖strlen、memcpy,同时支持混合传入字符串字面量和constexpr函数返回的字符串:
#include <array> #include <cstddef> // 可作为非类型模板参数的编译期固定字符串类 template<size_t N> struct FixedString { // 支持从字符串字面量构造 constexpr FixedString(const char (&str)[N]) noexcept { for (size_t i = 0; i < N; ++i) data[i] = str[i]; } // 支持从字符数组指针+长度构造 constexpr FixedString(const char* str, size_t len) noexcept requires(N >= 1) { for (size_t i = 0; i < len && i < N - 1; ++i) data[i] = str[i]; data[N - 1] = '\0'; } char data[N]{}; constexpr size_t size() const noexcept { return N - 1; } constexpr operator const char*() const noexcept { return data; } }; // 可变参数拼接函数 template<size_t... Ns> constexpr auto concat(FixedString<Ns>... strs) noexcept { // 计算拼接后的总长度 constexpr size_t total_len = (0 + ... + strs.size()) + 1; std::array<char, total_len> buf{}; size_t pos = 0; // 逐个写入所有字符串内容 auto write = [&](const auto& s) { for (size_t i = 0; i < s.size(); ++i) buf[pos++] = s.data[i]; }; (write(strs), ...); buf[pos] = '\0'; return FixedString<total_len>(buf.data(), total_len); } // 测试用:返回编译期字符串的函数 constexpr FixedString<6> get_custom_str() noexcept { return "test_"; }
使用示例(直接用于static_assert)
int main() { // 混合拼接字符串字面量和constexpr函数返回值 constexpr auto combined_str = concat( FixedString("prefix_"), get_custom_str(), FixedString("suffix") ); // 直接在static_assert中使用 static_assert(combined_str.size() == 17); static_assert(combined_str[0] == 'p'); // 完整内容校验 static_assert([]{ const char expected[] = "prefix_test_suffix"; for (size_t i = 0; i < sizeof(expected); ++i) { if (combined_str[i] != expected[i]) return false; } return true; }()); return 0; }
C++17兼容方案
如果不支持C++20的类类型非类型模板参数,可以通过constexpr lambda和std::array实现,不需要模板参数传递字符串:
#include <array> #include <cstddef> // 拼接多个字符串字面量 template<size_t... Ns> constexpr auto concat_strs(const char (&... strs)[Ns]) noexcept { constexpr size_t total_len = (0 + ... + (Ns - 1)) + 1; std::array<char, total_len> res{}; size_t pos = 0; auto write = [&](const char* s, size_t len) { for (size_t i = 0; i < len; ++i) res[pos++] = s[i]; }; (write(strs, Ns - 1), ...); res[pos] = '\0'; return res; } // 测试用:返回编译期字符串的函数 constexpr std::array<char, 6> get_custom_str() noexcept { return {'t','e','s','t','_','\0'}; }
使用示例
int main() { constexpr auto combined_str = []{ const auto part1 = concat_strs("prefix_"); const auto part2 = get_custom_str(); const auto part3 = concat_strs("suffix"); constexpr size_t total_len = (part1.size() - 1) + (part2.size() - 1) + (part3.size() - 1) + 1; std::array<char, total_len> res{}; size_t pos = 0; for (char c : part1) if (c) res[pos++] = c; for (char c : part2) if (c) res[pos++] = c; for (char c : part3) if (c) res[pos++] = c; res[pos] = '\0'; return res; }(); static_assert(combined_str.size() == 18); static_assert(combined_str[0] == 'p'); return 0; }
内容的提问来源于stack exchange,提问作者DiKetarogg
相关产品推荐
相关产品推荐

