你可以拥有永远无法实例化的模板吗?

huangapple go评论71阅读模式
英文:

Are you allowed to have templates that can never be instantiated?

问题

I vaguely recall a rule that states that variadic function templates have to be instantiable with more than just an empty pack. Do similar rules apply to templates in general?

例如:

template <int N>
struct array {
    // when instantiated, always ill-formed
    // however, expression is dependent on N, so the compiler allows this
    int arr[N * 0];
};

template <int N>
void foo() {
    int arr[N * 0]; // same as above
}

上面的代码是非法的,不需要诊断,还是合法的吗?如果我们为array定义了一个部分特化,以使主模板不可能被实例化呢?

template <int N>
requires true
struct array<N> {};
英文:

I vaguely recall a rule that states that variadic function templates have to be instantiable with more than just an empty pack. Do similar rules apply to templates in general?

For example:

template <int N>
struct array {
    // when instantiated, always ill-formed
    // however, expression is dependent on N, so the compiler allows this
    int arr[N * 0];
};

template <int N>
void foo() {
    int arr[N * 0]; // same as above
}

Is the above code ill-formed, no diagnostic required, or is it well-formed? What if we defined a partial specialization for array so that it becomes impossible to instantiate the primary template?

template <int N>
requires true
struct array<N> {};

答案1

得分: 4

是的,它是IFNDR,根据temp.res.general/8.1,假设您从不尝试实例化(主要)模板(否则将被视为无法诊断的错误)。部分特化是否存在并不重要。这不会改变主要模板无法对任何有效的特化进行实例化的事实。

这个规则的目的可能是(我实际上不知道有没有任何文件说明)为了允许编译器识别您编写的模板定义是荒谬的,几乎肯定是一个错误,然后拒绝编译包含它的程序。以这种方式编写主要模板有什么意义呢?

然而,从语言专家的角度来看,IFNDR实际上意味着对于处理IFNDR程序,编译器不放置任何要求,因此它也可以将其编译成具有任何任意行为的可执行文件。如果上述理由是有意的,那么标准可以明确写明编译是否会失败是未指定的。

如果目标是在主要模板被实例化时提供某种特定形式的诊断,尽管它永远不应该被实例化,或者如果目标是防止特化被默默地视为不完整,可以使用static_assert(false, "message");。最近,通过解决CWG 2518的缺陷报告,已为此用例添加了一个总是失败的static_asserttemp.res.general/8.1的异常。

英文:

> Is the above code ill-formed, no diagnostic required, or is it well-formed? What if we defined a partial specialization for array so that it becomes impossible to instantiate the primary template?

Yes, it is IFNDR because of [temp.res.general]/8.1, assuming that you never try to instantiate the (primary) template (and otherwise it is ill-formed with a diagnostic required). Whether the partial specialization is present doesn't matter. It doesn't change anything about the fact that the (primary) template cannot be instantiated for any valid specialization.

The point of the rule was probably (I don't actually know of any documents stating the rationale) for the compiler to be allowed to recognize that the template definition you wrote is nonsensical and almost surely a mistake and to then refuse compiling the program containing it. What would be the point of writing your primary template this way?

However, from a language lawyer perspective IFNDR actually means that no requirements are placed on the compiler for handling the IFNDR program at all, so that it may also e.g. compile it to an executable with any arbitrary behavior. If the above rationale was intended, the standard could have been written to say specifically that whether or not the compilation will fail is unspecified.

If the goal is to provide some specific form of diagnostic if the primary template is instantiated although it never should be, or if the goal is to prevent a specialization to be silently considered incomplete, static_assert(false, "message"); can be used. An exception to [temp.res.general]/8.1 has been added for an always-failing static_assert recently as a defect report via resolution of CWG 2518 for this use case.

huangapple
  • 本文由 发表于 2023年6月15日 02:51:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76476720.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定