constexpr 静态成员 before/after C++17

constexpr static member before/after C++17

据我所知,很常见的情况是

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

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

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

现在我读到 cppreference: Definitions and ODR and cppreference: static members,它指出 C++17 已弃用它。这对我来说似乎很棒,因为它避免了很多错误。但是还有其他问题:

1) 除了使附加定义无用之外,这是否改变了其他原因? (另请参阅此问题的最后一段)

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

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

简要说明 C++17 之前和 C++17 的最佳实践会很棒。总而言之,这对我来说似乎是一个非常棘手的改变,因为它将使很多代码(以前是 "ill-formed non diagnostic required")变成好的代码(据我了解......)。因此会产生代码,仍然是 "ill-formed non diagnostic required" 旧的(17 之前的)编译器 - 但这些不会抱怨,只要不需要 odr-use。

编辑:更正文本,由 Aaron McDaid 建议。

此更改是由于内联变量提议 (P0386)。 static constexpr 将暗示 inline,使定义变得多余。

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.

[Example:

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

—end example]

关于您的问题:

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

本质上,没有。然而,除了您提到的用途之外,它还有其他用途(参见 )。这个提议是有争议的,因为它可能会鼓励使用可变的全局状态。

Will it apply on const static member or not?

没有。 除非您将其注释为inline

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

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