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

为何无法将字符串字面量传入const auto&类型非类型模板参数(NTTP)

问题

先看最小复现代码:

template<const auto& A>
class B {};

int main() {
    B<"abc"> b;
    return 0;
}

上述代码无论怎么调整变体都无法编译通过,但CTRE库却支持类似写法:

constexpr auto match(std::string_view sv) noexcept {
    return ctre::match<"h.*">(sv);
}

该库的模板同样声明了const auto&类型形参,参数经过接收、类型别名定义、转发、最终使用的完整链路都没有编译错误。

自行实现同类逻辑时同样遇到编译报错,相关代码如下:

template<const auto& StringParameterConstant, size_t IndexParameterConstant = 0>
consteval size_t string_length()
{
    if constexpr(StringParameterConstant[IndexParameterConstant] != '\0')
        return string_length<StringParameterConstant, IndexParameterConstant + 1>();
    else
        return IndexParameterConstant;
}

template<char... CharacterParameterConstants>
struct TemplateString {
    constexpr static const size_t length = sizeof...(CharacterParameterConstants);
    constexpr static const char array[length] = { CharacterParameterConstants... };
};

template<
        const auto& StringParameterConstant, 
        size_t IndexParameterConstant, 
        size_t LengthParameterConstant, 
        char... CharacterParameterConstants
    >
consteval auto to_template_string()
{
//...
}
template<const auto& StringParameterConstant>
    using TemplateStringType = decltype(to_template_string //...
template<
            const auto& PatternParameterConstant,
            const auto& NameParameterConstant, //...
        >
    struct RegexTerm
    {
        using PatternType = TemplateStringType<PatternParameterConstant>;
        using NameType = TemplateStringType<NameParameterConstant>;
        constexpr static ctpg::regex_term<PatternType::string> term( // OK
                NameType::string, // OK
                //...
            );
    };
//...
// 尝试过constexpr static、放在consteval/constexpr函数内等写法均失败
RegexTerm<"[1-9][0-9]*", "Numerical">::term; // 编译错误

解答

编译失败核心原因

报错本质是违反了C++非类型模板参数(NTTP)的绑定规则:

  • 声明为const auto&的引用类型模板形参,要求绑定的实参必须是静态存储期、编译期可唯一确定身份的常量对象。
  • 直接传入的字符串字面量本质是编译器临时生成的const char数组,标准没有规定同内容字符串字面量的存储唯一性,编译器无法在模板实例化阶段确认其固定身份,因此不允许直接绑定到引用类型NTTP,触发编译错误。

CTRE的实现原理

CTRE并没有直接将原始字符串字面量绑定到引用形参,它做了两层关键转换绕过了这个限制:

  • 首先定义了一个符合C++20类类型NTTP要求的固定长度字符串结构体,类似你实现的TemplateString,这类字面量类型可以按值作为模板参数传递,不需要绑定引用。
  • 库自定义了consteval字符串字面量运算符,你写的"h.*"作为模板参数传入时,会先被这个运算符转换成上述固定长度字符串结构体的编译期常量,后续链路里的const auto&形参,绑定的都是这个已经确定身份的静态常量,完全符合语法要求。

修复方案

不需要复刻CTRE的完整复杂链路,两种简单改法即可解决问题:

  1. 移除参数的引用修饰:C++20已经原生支持数组、字面量结构体作为值类型NTTP,直接把模板形参从const auto&改为auto,就可以直接接收字符串字面量,不需要额外处理存储期问题,改造成本最低。
  2. 增加字面量转换层:如果必须保留引用类型形参,自行实现一个consteval字面量运算符,将传入的原始字符串构造成静态存储期的固定长度字符串常量,再将这个常量传入模板即可。

内容的提问来源于stack exchange,提问作者cgbsu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:45:44