【问题标题】:Understanding static constexpr member variables理解静态 constexpr 成员变量
【发布时间】:2015-12-02 21:43:50
【问题描述】:

我对 C++11 中的 static constexpr 成员变量有些困惑。

在 first.hpp 中

template<typename T>
struct cond_I
{ static constexpr T value = 0; }; 


// specialization 
template<typename T>
struct cond_I< std::complex<T> >
{ static constexpr std::complex<T> value = {0,1}; }; 

在 main() 函数中

cout << cond_I<double>::value << endl;            // this works fine
cout << cond_I< complex<double> >::value << endl; // linker error

但是,如果我将以下行添加到 first.hpp 一切正常。

template<typename T1> 
constexpr std::complex<T1> cond_I< std::complex<T1> >::value;

我的理解(我可能错了)是,cond_I&lt; std::complex&lt;double&gt; &gt;::value 需要一个定义,但在前一种情况下它只有声明。但是cond_I&lt;double&gt;::value 呢?为什么不需要定义?

再次,在另一个头文件second.hpp 中,我有:

在 second.hpp 中

// empty struct
template<typename T>
struct eps
{ };


// special cases
template<>
struct eps<double>
{
  static constexpr double value = 1.0e-12;
};

template<>
struct eps<float>
{
  static constexpr float value = 1.0e-6;
};

在这种情况下,以下代码可以在没有任何eps&lt;&gt;::value 定义的情况下完美运行。

在 main() 函数中

cout << eps<double>::value << endl;    //  works fine
cout << eps<float>::value << endl;     //  works fine

谁能解释一下static constexpr成员变量在这些场景中的不同行为?

gcc-5.2clang-3.6 的这些行为也相同。

【问题讨论】:

  • 我认为答案是因为ostream::operator&lt;&lt;(ostream&amp;, const complex&lt;T&gt; &amp;)通过引用传递,这被认为是参数的odr-use,因此您需要一个定义(供引用参考到)。
  • 是的。无需任何参考,第一个代码就可以工作。 floatdouble 是按值传递的,所以第二个代码有效。谢谢。
  • @vsoftco 感谢您的来信。该线程包含一些有用的解释。我之前没找到。

标签: c++ c++11 constexpr


【解决方案1】:

根据标准9.4.2/p3 静态数据成员[class.static.data]Emphasis Mine):

如果一个非易失性 const 静态数据成员是整数或枚举类型,它在类定义中的声明可以指定一个大括号或等式初始化器,其中每个作为赋值表达式的初始化器子句都是一个常量表达式 (5.20)。 可以在类定义中使用constexpr 说明符声明文字类型的静态数据成员;如果是这样,它的声明应指定一个大括号或等式初始化器,其中作为赋值表达式的每个初始化器子句都是一个常量表达式。 [注:在这两个 在这些情况下,成员可能出现在常量表达式中。 — 尾注] 如果该成员在程序中被 odr-used (3.2) 使用并且命名空间范围定义不应 包含一个初始化程序。

正如 M.M 之前在 cmets ostream::operator&lt;&lt;(ostream&amp;, const complex&lt;T&gt;&amp;) 中解释的那样,通过引用传递,因此值被认为是程序中使用的 odr。因此,正如上面的措辞所要求的,您必须提供一个定义。

现在您已经发现基本类型是按值传递的,这就是不需要定义的原因。

【讨论】:

    猜你喜欢
    • 2019-08-02
    • 2018-08-06
    • 1970-01-01
    • 2021-08-07
    • 2016-06-25
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    相关资源
    最近更新 更多