简体   繁体   English

浮点类型作为 C++20 中的模板参数

[英]Floating-point types as template parameter in C++20

According to cppreference C++20 now supports floating-point parameters in templates.根据cppreference ,C++20 现在支持模板中的浮点参数。 I am, however, unable to find any compiler support information on that site as well as on others.但是,我无法在该站点以及其他站点上找到任何编译器支持信息。 Current gcc trunk just does it, the others are negative.当前 gcc 中继只是这样做,其他都是负面的。

I would just like to know if this is a very low-priortity feature and/or when to expect it to become commonly supported.我只想知道这是否是一个非常低优先级的功能和/或何时期望它得到普遍支持。

The only related thing I can find is: P0732R2 Class types in non-type template parameters.我能找到的唯一相关内容是:P0732R2 Class types in non-type template parameters。 Kudos if anyone could briefly explain that instead.如果有人能简单地解释一下,那就太好了。

It seems that the real question that can be answered here is about the history of this feature, so that whatever compiler support can be understood in context.似乎这里可以回答的真正问题是关于此功能的历史,因此可以在上下文中理解任何编译器支持。

Limitations on non-type template parameter types非类型模板参数类型的限制

People have been wanting class-type non-type template parameters for a long time.人们一直想要类类型的非类型模板参数 The answers there are somewhat lacking;那里的答案有些缺乏; what really makes support for such template parameters (really, of non-trivial user-defined types) complicated is their unknown notion of identity : given真正使对此类模板参数(实际上是非平凡的用户定义类型)的支持变得复杂的是它们未知的身份概念:给定

struct A {/*...*/};
template<A> struct X {};
constexpr A f() {/*...*/}
constexpr A g() {/*...*/}
X<f()> xf;
X<g()> &xg=xf;  // OK?

how do we decide whether X<f()> and X<g()> are the same type?我们如何确定X<f()>X<g()>是否是同一类型? For integers, the answer seems intuitively obvious, but a class type might be something like std::vector<int> , in which case we might have对于整数,答案似乎很直观,但 class 类型可能类似于std::vector<int> ,在这种情况下我们可能有

// C++23, if that
using A=std::vector<int>;
constexpr A f() {return {1,2,3};}
constexpr A g() {
  A ret={1,2,3};
  ret.reserve(1000);
  return ret;
}

and it's not clear what to make of the fact that both objects contain the same values (and hence compare equal with == ) despite having very different behavior ( eg , for iterator invalidation).尽管两个对象具有非常不同的行为例如,对于迭代器失效),但尚不清楚这两个对象包含相同(因此与==比较相等)的事实。

P0732 Class types in non-type template parameters P0732 Class 非类型模板参数中的类型

It's true that this paper first added support for class-type non-type template parameters, in terms of the new <=> operator.的确,这篇论文首先在新的<=>运算符方面添加了对类类型非类型模板参数的支持。 The logic was that classes that defaulted that operator were "transparent to comparisons" (the term used was "strong structural equality") and so programmers and compilers could agree on a definition of identity.其逻辑是默认该运算符的类是“对比较透明的”(使用的术语是“强结构相等”),因此程序员和编译器可以就标识的定义达成一致。

P1185 <=> != == P1185 <=> != ==

Later it was realized that == should be separately defaultable for performance reasons ( eg , it allows an early exit for comparing strings of different lengths), and the definition of strong structural equality was rewritten in terms of that operator (which comes for free along with a defaulted <=> ).后来意识到==出于性能原因应该单独默认(例如,它允许提前退出以比较不同长度的字符串),并且根据该运算符重写了强结构相等的定义(它是免费提供的)使用默认的<=> )。 This doesn't affect this story, but the trail is incomplete without it.这不会影响这个故事,但没有它,这条路是不完整的。

P1714 NTTP are incomplete without float, double, and long double! P1714 NTTP 没有 float、double 和 long double 是不完整的!

It was discovered that class-type NTTPs and the unrelated feature of constexpr std::bit_cast allowed a floating-point value to be smuggled into a template argument inside a type like std::array<std::byte,sizeof(float)> .发现类类型 NTTP 和constexpr std::bit_cast的不相关特性允许将浮点值走私到类似std::array<std::byte,sizeof(float)>的类型内的模板参数中. The semantics that would result from such a trick would be that every representation of a float would be a different template argument, despite the fact that -0.0==0.0 and (given float nan=std::numeric_limits<float>::quiet_NaN(); ) nan!=nan .这种技巧产生的语义,尽管-0.0==0.0和(给定float float nan=std::numeric_limits<float>::quiet_NaN(); ) nan!=nan It was therefore proposed that floating-point values be allowed directly as template arguments, with those semantics, to avoid encouraging widespread adoption of such a hacky workaround.因此,建议直接允许浮点值作为模板 arguments,具有这些语义,以避免鼓励广泛采用这种 hacky 解决方法。

At the time, there was a lot of confusion around the idea that (given template<auto> int vt; ) x==y might differ from &vt<x>==&vt<y> ), and the proposal was rejected as needing more analysis than could be afforded for C++20.当时,围绕(给定template<auto> int vt;x==y可能与&vt<x>==&vt<y>不同的想法存在很多混淆,并且该提案因需要而被拒绝比 C++20 所能提供的分析更多。

P1907R0 Inconsistencies with non-type template parameters P1907R0与非类型模板参数不一致

It turns out that == has a lot of problems in this area.结果发现==在这方面有很多问题。 Even enumerations (which have always been allowed as template parameter types) can overload == , and using them as template arguments simply ignores that overload entirely.甚至枚举(一直被允许作为模板参数类型)也可以重载== ,并且将它们用作模板 arguments 会完全忽略该重载。 (This is more or less necessary: such an operator might be defined in some translation units and not others, or might be defined differently, or have internal linkage, etc .) Moreover, what an implementation needs to do with a template argument is canonicalize it: to compare one template argument (in, say, a call) to another (in, say, an explicit specialization) would require that the latter had somehow already been identified in terms of the former while somehow allowing the possibility that they might differ. (这或多或少是必要的:这样的运算符可能在某些翻译单元中定义,而不是在其他翻译单元中定义,或者可能定义不同,或者具有内部链接。)此外,实现需要对模板参数做的是规范化它:一个模板参数(在调用中)与另一个模板参数(在显式特化中)进行比较需要后者已经以某种方式根据前者被识别,同时以某种方式允许它们可能不同的可能性.

This notion of identity already differs from == for other types as well.这种身份的概念已经不同于其他类型的== Even P0732 recognized that references (which can also be the type of template parameters) aren't compared with == , since of course x==y does not imply that &x==&y .甚至 P0732 也认识到引用(也可以是模板参数的类型)不会与==进行比较,因为当然x==y并不意味着&x==&y Less widely appreciated was that pointers-to-members also violate this correspondence: because of their different behavior in constant evaluation, pointers to different members of a union are distinct as template arguments despite comparing == , and pointers-to-members that have been cast to point into a base class have similar behavior (although their comparison is unspecified and hence disallowed as a direct component of constant evaluation).不太受欢迎的是指向成员的指针也违反了这种对应关系:由于它们在不断评估中的不同行为,指向联合不同成员的指针作为模板 arguments 是不同的,尽管比较== ,并且指向成员的指针已经被转换为指向基数 class 具有类似的行为(尽管它们的比较未指定,因此不允许作为常量评估的直接组成部分)。

In fact, in November 2019 GCC had already implemented basic support for class-type NTTPs without requiring any comparison operator.事实上,在 2019 年 11 月 GCC 已经实现了对类类型 NTTP 的基本支持,不需要任何比较运算符。

P1837 Remove NTTPs of class type from C++20 P1837从 C++20 中移除 class 类型的 NTTP

These incongruities were so numerous that it had already been proposed that the entire feature be postponed until C++23.这些不协调的地方太多了,以至于已经有人提议将整个特性推迟到 C++23。 In the face of so many problems in so popular a feature, a small group was commissioned to specify the significant changes necessary to save it.面对如此受欢迎的功能存在如此多的问题,一个小组被委托指定必要的重大更改来保存它。

P1907R1 (structural types) P1907R1 (结构型)

These stories about template arguments of class type and of floating-point type reconverge in the revision of P1907R0 which retained its name but replaced its body with a solution to National Body comments that had also been filed on the same subject.这些关于模板 arguments 的 class 类型和浮点类型的故事在 P1907R0 的修订版中重新汇合,该修订版保留了它的名称,但用一个解决方案替换了它的正文,以解决同样在同一主题上提交的国家机构评论。 The (new) idea was to recognize that comparisons had never really been germane, and that the only consistent model for template argument identity was that two arguments were different if there was any means of distinguishing them during constant evaluation (which has the aforementioned power to distinguish pointers-to-members, etc. ). (新)想法是要认识到比较从来没有真正密切相关,并且模板参数标识唯一一致的 model 是两个 arguments 是不同的,如果在持续评估期间有任何区分它们的方法(具有上述权力区分指向成员的指针)。 After all, if two template arguments produce the same specialization, that specialization must have one behavior, and it must be the same as would be obtained from using either of the arguments directly.毕竟,如果两个模板 arguments 产生相同的特化,则该特化必须有一个行为,并且它必须与直接使用 arguments 中的任何一个获得的行为相同。

While it would be desirable to support a wide range of class types, the only ones that could be reliably supported by what was a new feature introduced (or rather rewritten) at almost the last possible moment for C++20 were those where every value that could be distinguished by the implementation could be distinguished by its clients—hence, only those that have all public members (that recursively have this property).虽然支持广泛的 class 类型是可取的,但几乎在最后可能的时刻为 C++20 引入(或更确切地说重写)的新功能能够可靠地支持的唯一类型是那些每个值可以通过实现来区分的可以通过它的客户来区分——因此,只有那些拥有所有公共成员(递归地拥有这个属性)的人。 The restrictions on such structural types are not quite as strong as those on an aggregate, since any construction process is permissible so long as it is constexpr.对此类结构类型的限制不如对聚合的限制那么严格,因为任何构造过程都是允许的,只要它是 constexpr。 It also has plausible extensions for future language versions to support more class types, perhaps even std::vector<T> —again, by canonicalization (or serialization) rather than by comparison (which cannot support such extensions).它还对未来的语言版本进行了合理的扩展,以支持更多的 class 类型,甚至可能是std::vector<T> ——同样,通过规范化(或序列化)而不是通过比较(无法支持此类扩展)。

The general solution通用解决方案

This newfound understanding has no relationship to anything else in C++20;这种新发现的理解与 C++20 中的任何其他内容都没有关系; class-type NTTPs using this model could have been part of C++11 (which introduced constant expressions of class type).使用此 model 的类类型 NTTP 可能是C++11的一部分(它引入了 class 类型的常量表达式)。 Support was immediately extended to unions, but the logic is not limited to classes at all;支持立即扩展到联合,但逻辑根本不限于类; it also established that the longstanding prohibitions of template arguments that were pointers to subobjects or that had floating-point type had also been motivated by confusion about == and were unnecessary.它还确定,模板 arguments 的长期禁令是指向子对象的指针或具有浮点类型,这也是由于对==的混淆而引起的,并且是不必要的。 (While this doesn't allow string literals to be template arguments for technical reasons, it does allow const char* template arguments that point to the first character of static character arrays.) (虽然出于技术原因这不允许字符串文字为模板 arguments,但它确实允许指向 static 字符 arrays 的第一个字符的const char*模板 arguments。)

In other words, the forces that motivated P1714 were finally recognized as inevitable mathematical consequences of the fundamental behavior of templates and floating-point template arguments became part of C++20 after all.换句话说,推动 P1714 的力量最终被认为是模板基本行为的不可避免的数学结果,而浮点模板 arguments 毕竟成为了 C++20 的一部分。 However, neither floating-point nor class-type NTTPs were actually specified for C++20 by their original proposals, complicating "compiler support" documentation.然而,无论是浮点还是类类型的 NTTPs 都没有在他们最初的提案中为 C++20 指定,这使得“编译器支持”文档变得复杂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM