C++17 之前/之后的 constexpr 静态成员

2022-01-05 00:00:00 static c++ c++17 constexpr

据我所知,一个很常见的情况是这样的

As far as I can see, a very common situation is something like

template<int i> class Class
{
public:
    static constexpr int I = i;
    static constexpr int J = constexprFunction(i);
    // further Class implementation
};

几乎和我一样常见的错误(实际上我在这里的大部分问题都是因为我忘记了它并且不知道正确的问题是什么)如果成员被 odr 使用,则忘记了附加定义:

Almost as common I see the mistake (in fact most of my questions here are because I forgot it and did not know, what the proper question had been) to forget the additional definition if the member are odr-used:

template<int i> constexpr int Class<i>::I;
template<int i> constexpr int Class<i>::J;

现在我阅读了cppreference:定义和 ODR 和 cppreference: 静态成员,其中指出 C++17 已弃用此功能.这对我来说似乎很棒,因为它避免了很多错误.但是还有其他问题出现了:

Now I read cppreference: Definitions and ODR and cppreference: static members, which state, that this is deprecated for C++17. This seems great to me, because it avoids a lot of errors. But there are other questions, that came up:

1) 除了使附加定义无用之外,这种变化是否还有其他原因?(另见本问题的最后一段)

1) Has this change other reasons than making the additional definitions useless? (See also last paragraph of this question)

2) 在 cppreference: static members 的最后一个例子中,它似乎也是应用于 const static 成员 - 但规则仅声明 constexpr 成员.它是否适用于 const static 成员?

2) In the last example of cppreference: static members it seems also to apply on const static member - but the rule states only the constexpr member. Will it apply on const static member or not?

3) 我发现的所有例子都使用了一个简单的定义,比如 Class::I - 它是否也适用于 Class:J 的情况constexpr 函数?

3) All examples I found were using a simple definition like Class::I - does it all hold also for the situation at Class:J with constexpr functions?

简要说明在 C++17 之前和使用 C++17 的最佳实践是什么会很棒.总而言之,这对我来说似乎是一个非常棘手的变化,因为它会使很多代码,以前格式错误,不需要诊断",变成好的代码(据我所知......).因此,将生成代码,对于较旧的(17 版之前)编译器,这仍然是格式错误的非诊断所需" - 但只要不需要 odr-use,这些代码就不会抱怨.

A brief state what the best practices are before C++17 and with C++17 would be great. All in all this seems a very tricky change to me, because it will make a lot of code, which was "ill-formed non diagnostic required" before, to good code (as far as I understand...). And consequently there will be code produced, that is still "ill-formed non diagnostic required" with older (pre 17) compiler - but these will not complain, as long as no odr-use is required.

编辑:更正了 Aaron McDaid 建议的文本.

Edit: Corrected the text, suggested by Aaron McDaid.

推荐答案

此更改是由于内联变量提案 (P0386).static constexpr 将意味着 inline,使定义变得多余.

This change is due to the inline variables proposal (P0386). static constexpr will imply inline, making definitions redundant.

在附录 D 中,添加新的子条款静态 constexpr 数据成员的重新声明",D.X,内容如下:为了与之前的 C++ 国际标准兼容, constexpr 静态数据成员可以在没有初始化程序的类之外冗余地重新声明.此用法已弃用.

In Annex D, add a new subclause, "Redeclaration of static constexpr data members", D.X, with the following content: For compatibility with prior C++ International Standards, a constexpr static data member may be redundantly redeclared outside the class with no initializer. This usage is deprecated.

[示例:

struct A {
static constexpr int n = 5; // definition (declaration in C++2014)
};
const int A::n; // redundant declaration (definition in C++2014)

――结束示例]

关于您的问题:

除了使附加定义无用之外,这种变化是否还有其他原因?

Has this change other reasons than making the additional definitions useless?

本质上,没有.然而,除了您指出的用途之外,它还有其他用途(请参阅此 问题).这个提议是有争议的,因为它可能鼓励使用可变的全局状态.

In essence, no. Yet it has additional uses besides the one you noted (see this question). This proposal was controversial because it might encourage the use of a mutable global state.

它是否适用于 const static 成员?

Will it apply on const static member or not?

没有.除非将其注释为inline.

这是否也适用于 Class:Jconstexpr 函数的情况?

does it all hold also for the situation at Class:J with constexpr functions?

是的.该提案涉及链接但不影响初始化规则.

Yes. The proposal deals with linking but does not affect initialization rules.

相关文章