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

为何此场景下非类型模板参数不能使用auto?

为什么这个C++场景下会报错“非类型模板参数不能使用auto”?

问题代码

#include <variant>
template <auto V>
using ic = std::integral_constant<decltype(V), V>;
enum { shake };
int milk(ic<shake>);
template <class...>
struct context {
    template <auto V>
    decltype(milk(ic<V>{})) get() {
        return std::get<decltype(milk(ic<V>{}))>(value);
    }
    std::variant<int> value;
};
int main(){
    context<int> c;
    c.get<shake>();
}

编译错误(Clang)

prog.cc:13:42: error: a non-type template parameter cannot have type 'auto'
return std::get<decltype(milk(ic{}))>(value);
^
prog.cc:3:16: note: template parameter is declared here
template
^
1 error generated.

问题分析

先澄清一个关键点:template <auto V>本身是完全合法的——C++17及以后标准支持用auto作为非类型模板参数的占位符,错误提示的指向其实有误导性,真正的问题出在std::get的模板参数使用上。

std::get针对std::variant有两个重载模板:

  • 一个接受类型参数(比如std::get<int>(var)),用于按类型提取variant的值(要求该类型在variant中唯一存在);
  • 另一个接受非类型的std::size_t参数(比如std::get<0>(var)),用于按索引提取。

你的代码中,decltype(milk(ic<V>{}))的结果是int,理论上std::get<int>(value)是合法的类型参数调用,但因为这个类型是依赖于模板参数V的依赖类型,编译器在解析模板时没能正确识别它是类型参数,反而错误地将其当作了非类型参数处理。而std::get的非类型参数要求必须是std::size_t类型,这就触发了错误提示(错误信息关联到auto模板参数是因为整个表达式依赖于V)。

解决方法

你可以通过以下两种方式修复代码:

方法1:明确提取类型别名

通过using声明把依赖类型显式提取出来,让编译器清楚这是一个类型参数:

template <class...>
struct context {
    template <auto V>
    decltype(milk(ic<V>{})) get() {
        using ResultType = decltype(milk(ic<V>{}));
        return std::get<ResultType>(value);
    }
    std::variant<int> value;
};

方法2:直接按索引获取

既然你的std::variant只包含int一种类型,也可以直接用索引0来获取值,避免类型解析的歧义:

template <class...>
struct context {
    template <auto V>
    decltype(milk(ic<V>{})) get() {
        return std::get<0>(value);
    }
    std::variant<int> value;
};

内容的提问来源于stack exchange,提问作者W.F.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:16:55