为什么GCC认为constexpr静态数据成员的定义必须标记为constexpr?

时间:2015-06-14 16:05:55

标签: c++ gcc c++14 constexpr

  

[C++14: 7.1.5/1]: constexpr说明符只能应用于变量或变量模板的定义,函数或函数模板的声明,或文字类型的静态数据成员的声明(3.9)。如果函数,函数模板或变量模板的任何声明都具有constexpr说明符,则其所有声明都应包含constexpr说明符。 [..]

请注意,第二句没有提到"静态数据成员"第一句话的方式,因此本段落中没有要求constexpr static数据成员的所有声明(此处我特别考虑定义声明)都具有{{ 1}}说明符。

我无法在其他地方找到规则来强制执行此操作。

那么,为什么海湾合作委员会拒绝接受以下计划?

constexpr

3 个答案:

答案 0 :(得分:2)

这看起来对我来说没有具体说明,我没有看到一个明确的要求,但是我们可以看到为什么这是来自defect report 699: Must constexpr member functions be defined in the class member-specification? 的问题,虽然处理constexpr成员函数说明如下(强调我的):

  

如果放宽禁令以允许单独声明和   constexpr成员函数的定义,需要一些问题   回答,例如constexpr说明符是否必须出现   声明和定义(内联说明符不需要)。如果它   可以在一个或另一个中省略,存在可用性问题   关于constexpr意味着const的事实; const限定符   需要在声明中明确指定   constexpr被省略。

虽然在这种情况下添加const并不能解决问题,但在更简单的情况下它似乎解决了这个问题。我们可以在更简单的情况下看到clang和gcc都需要const或constexpr:

struct T
{
   static constexpr int blah = 1 ;
};

const int T::blah ;

更新

此gcc错误报告: Bogus "error: redeclaration ... differs in ‘constexpr’"引用了Richard Smith的以下引文:

  

没有规则要求连续声明变量   同意'constexpr'ness(此规则仅适用于函数)。

所以这看起来像一个gcc bug,虽然它似乎仍然可以在标准中使用一些清晰度。

答案 1 :(得分:0)

根据7.1.5(9),必须在课堂上初始化constexpr静态数据成员。这是该成员的定义。由于ODR不允许其他定义,因此T :: dur_1只能是声明。但是没有规则允许在类体外声明const静态数据成员,因此不允许此声明。

只有在始终如一地使用constexpr时,GCC才支持此扩展。

或者我错了,这是一个错误;)

FWIW:clang在没有警告的情况下接受此代码。

答案 2 :(得分:-1)

My previous answer thought that the problem with the code was that the std::chrono_literals objects were not valid as constexps, but as pointed out by Lightspeed, this is not the case.

I did a little more research and determined that the problem line with your code is your struct t: specifically this line:

static constexp auto ...

There is another answer on SO about this here

To explicitly point out why this is your issue (as the comment indicates this is not immediately obvious):

Any expression labeled constexp is to be determined at compile-time. This much you know already. When you try and instantiate with the decltype(T::dur_1) T:dur_1 expression, in your eyes you are providing the proper credentials to the chrono literal constructor (which is constexp). The issue is that the type is not explicitly defined as you seem to think it is from your pre-processor definition of the DUR replacement of 1000ms.

Try the following:

template <class T>
struct foo {
    static constexpr auto dur_1 = DUR;
    typedef decltype(DUR) milliseconds;
}

template <class T>
constexp milliseconds foo<T>::milliseconds foo<T>::DUR; 

By removing the inability of the GCC compiler to determine the auto type at compile time through the explicit definition, you should solve your problem.

This is why the original link was given. GCC is incorrectly unable to determine the auto-typing at compile time.