【问题标题】:Misunderstanding about non-deducible function template arguments对不可演绎函数模板参数的误解
【发布时间】:2021-09-12 16:15:50
【问题描述】:

来自C++ 模板 - 完整指南第 2 版

此外,此类参数不能有用地放置在模板参数包之后或出现在部分特化中,因为无法显式指定或推导它们。

template<typename ...Ts, int N>
void f(double (&)[N+1], Ts ... ps); // useless declaration because N
                                    // cannot be specified or deduced

其中 此类参数 指的是(我认为)与那些永远无法推断的模板参数相对应的模板参数。 IE。上例中N是不能推导的参数,因为N+1“太复杂推导不了”。

但是为什么不能指定它呢?我知道不可能指定N 并推导出...Ts,但为什么不能全部指定呢?换句话说,通过以下方式指定Ts=[int]N=2 有什么问题?

    double x[3];
    f<int,2>(x,1);

【问题讨论】:

  • ... 太贪心了,它也消耗了2。当编译器意识到2 不是一种类型时,为时已晚。以其他方式做在理论上是可能的,但可能会使已经相当复杂的解析器复杂化。
  • 哦,好吧...由于模板参数的种类(非类型、类型和模板)很好分离,我没想到到时候可能是一个论点。例如,为什么编译器在查找类型时要消耗 2?
  • 在一般情况下,它们并没有很好地分开。例如,您可以将A 设为类型、using A = int; 或非类型constexpr int A = 2;。那么编译器会用f&lt;int, A&gt; 做什么呢?我的猜测是解析器甚至不会尝试在这里进行分析。
  • 我知道这是一个纯粹的理论问题,但值得一提的是,在实践中,这很少会成为问题,因为您可以将参数包放在模板参数列表的末尾。跨度>
  • @Enlico 我明白了。也许即使不完全相关的帖子也能稍微澄清一下。在您的示例中,如果编译器可以区分类型模板和非类型模板,它会起作用,但在其他情况下它可能会出现问题。因此标准对此非常严格:模板参数包之后的所有参数,无论非类型的类型必须是默认的还是可扣除的。

标签: c++ templates c++17 language-lawyer template-meta-programming


【解决方案1】:

即上例中N是不能推导的参数,因为N+1“太复杂推导不了”。

正式地,这是[temp.deduct.type]/5.3

未推断的上下文是:

  • [...]
  • /5.3 非类型模板参数或数组绑定其中子表达式引用模板参数

正如以下问答中已经介绍的那样:

尤其是在函数模板的模板头中

template<typename ...Ts, int N>
// ... function template

根据[temp.param]/14

函数模板的模板形参包后面不能有另一个模板形参除非该模板形参可以从parameter-type-list([dcl .fct]) 的函数模板或具有默认参数 ([temp.deduct])。

特别是根据函数模板的特殊规则(由于函数模板参数推导),模板参数N 必须从函数的参数列表中推导出来。根据[temp.deduct.type]/5.3,它不是,并且以下示例中的f 永远不能调用(重载决议永远不会认为它是可行的候选者):

template<typename ...Ts, int N>
void f(double (&)[N+1], Ts ... ps);

而以下函数都可以通过重载解析找到:

template<typename ...Ts, int N>
void g(double (&)[N], Ts ... ps);   // N deducible from function parameter

template<typename ...Ts, int N = 2> // N has a default-template-argument
void h(double (&)[N+1], Ts ... ps);

但是为什么不能指定呢?

正如链接到问答中所讨论的那样,尽管“编译器支持这一点是有意义的”,但标准不支持,并且领先的模板参数包贪婪地包含所有显式提供的模板参数,即使是那些不会作为扩展包的一部分有效(例如,类型模板参数包的非类型模板参数)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    • 2020-05-09
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多