You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++编译期拼接可变数量字符串字面量用于static_assert实现问题

报错原因说明

你遇到的两个报错都是C++标准的明确限制:

  1. 字符串字面量的地址无法作为模板非类型参数:标准规定字符串字面量的地址不具备常量表达式的唯一性要求,不同编译单元的相同字面量可能有不同地址,因此不允许用于模板参数。
  2. 完美转发的入参如果没有显式声明为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 00:27:05