【问题标题】:constexpr static member before/after C++17C++17 之前/之后的 constexpr 静态成员
【发布时间】:2021-09-10 03:07:29
【问题描述】:

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

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 ODRcppreference: static members,它们声明这对于 C++17 已弃用。这对我来说似乎很棒,因为它避免了很多错误。但是还有其他问题:

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

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

3) 我发现的所有示例都使用了像 Class::I 这样的简单定义 - 这是否也适用于 Class:J 的情况以及 constexpr 函数?

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

编辑:更正了 Aaron McDaid 建议的文字。

【问题讨论】:

  • 我认为关于静态数据成员的最后一个示例是编辑错误(现已修复):9.2.3.2[class.static.data]p3 说,对于“非易失性非内联 const 静态数据member", "如果成员被 odr-used,则仍应在命名空间范围内定义"
  • 我对当前问题中的文字感到困惑:“如果成员被 odr-used,则错误...给出定义”。当然,您的意思是,例如在 C++11 中,fail 给出定义是错误的吗?你忘了否定吗? (对不起,如果这看起来很迂腐,但我真的不太了解这一点,无法确定这里的意图)
  • @AaronMcDaid 是的,这是真的。我修好了它。我明确表示有必要在 C++11 中给出附加定义,但在 C++17 中不再如此。因此,我试图在最后一段中解释我对向下兼容目的的困惑。
  • @Cubbi:有没有可能,这个功能还没有在 gnu 编译器中实现?我用this question的MWE试了一下,用g++-6-std=C++17编译。它仍然抱怨缺乏定义!还是我在想一些愚蠢的事情?
  • @marlam 这个功能甚至没有在 gcc compliance status table 中列出。它在clang 3.9 中可用。它也可以在 MSVC 2015 中使用(尽管在这种情况下是因为缺乏标准)

标签: c++ static constexpr c++17


【解决方案1】:

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

在附件 D 中,添加一个新的子条款,“静态 constexpr 数据成员的重新声明”,D.X,其内容如下: 为了与以前的 C++ 国际标准兼容,constexpr 静态数据成员可以在没有初始化器的类外部冗余地重新声明。这种用法已被弃用。

[示例:

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

——结束示例]

关于您的问题:

除了使附加定义无用之外,还有其他原因吗?

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

它是否适用于const static 成员?

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

Class:J 的情况是否也适用于 constexpr 函数?

是的。该提案处理链接,但不影响初始化规则。

【讨论】:

  • 我知道这是一个引用,但是声明一个constexpr 并将其定义为const 是不是有点混乱?因为这在我看来是不一样的……
  • @marlam 这也让我感到惊讶。我认为这是一个错字。
  • OP的问题真的很难理解,英文措辞令人困惑。也许这不是直接问的,但是:static constexpr 的含义与 C++17 中的constexpr 相同吗?为什么我会在类声明中为常量成员变量使用一个或另一个,这总是让我感到困惑。如果是constexpr,就不能改了,那static不是多余的吗?同样现在如果constexpr 表示inline,是不是和说static inline 一样没有意义?
  • @void.pointer static constexpr 与 C++17 中的 static inline constexpr 相同,但单独使用 constexpr 并不意味着 inline constexpr。将static constexpr 用于成员变量(example in the standard)。将inline constexpr 用于全局变量 (example in the standard)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多