哪些值可以分配给`constexpr`参考?

时间:2014-09-30 13:21:36

标签: c++11 reference constexpr

原始问题

我想使用静态成员变量,以便通过类型模板参数将信息传递到模板化类中。不应在所有翻译单元中包含的头文件中设置这些变量,以便我可以更改它们而无需重新编译大多数目标文件。此外,为不需要额外空间的变量提供方便的别名会很好。我认为constexpr只读引用如

static constexpr const int& alias = T::static_variable_name;

可以作为这样的别名,但不确定这是否有效。 constexpr reads

的一个限制
  
      
  • 构造函数参数或要分配的值必须仅包含文字值,constexpr变量和函数。
  •   

所以我尝试使用g++ -std=c++11并根据自己的口味采取了一些不一致的行为。代码包含在此问题的末尾。在大多数情况下,代码编译并运行正常,但是当在非专用类模板中直接使用h2g2_oracle::answer时(请参阅注释“错误;为什么?”),编译失败并显示消息

src/main.cpp:18:57: error: the value of ‘h2g2_oracle::_answer’ is not usable
in a constant expression
      static constexpr const int& answer = h2g2_oracle::answer; // ERROR; WHY?
src/main.cpp:11:9: note: ‘int h2g2_oracle::_answer’ is not const
      int h2g2_oracle::_answer = 42;

为什么大多数constexpr个引用都是别名,而这个引用不是?

#include <iostream>

// a specific kind of oracle
class h2g2_oracle {
  protected:
    static int _answer;

  public:
    static constexpr const int& answer = _answer; // public alias for reading
};
int h2g2_oracle::_answer = 42;

// some class template using a specific kind of oracle
template<typename oracle>
struct forecast {
  // try to define an own alias
  static constexpr const int& answer = oracle::answer; // works
  //static constexpr const int& answer = h2g2_oracle::answer; // ERROR; WHY?
};

// specialized version for the h2g2_oracle
template<>
struct forecast<h2g2_oracle> {
  // also define the own alias
  static constexpr const int& answer = h2g2_oracle::answer; // works
};

int main() {
  static constexpr const int& answer = h2g2_oracle::answer; // works
  std::cout << answer << std::endl;

  std::cout << forecast<h2g2_oracle>::answer << std::endl;
  return 0;
}

解决评论

@Ben Voigt关于the gain of constexpr:是的,dyp is right with the assumption我喜欢constexpr版本,因为它在身体内进行初始化。 长评:我非常确定单独翻译单元中的初始化会强制程序使用存储原始地址的某个内存位置。因此,我认为constexpr可能对始终在标题中具有静态成员初始化有用,即对于模板(forecast<...>::answer)和非模板({{1} })。我知道我可以更改非模板类以包含虚拟模板参数,以便初始化也可以在标题中完成,但最初我觉得h2g2_oracle::answer的解决方案对我来说更容易。

关于possible g++ bug的@dyp:啊,我没想到会找到一个这样的“简单”测试。现在我看到了相关的问题,这对我来说似乎是一个很好的解释。我可以通过何种切实可行的方式确认/报告/帮助?如果你对此非常有信心,我至少可以接受这个答案。

关于definition before using

@dyp:是的,我检查过g ++在非专业constexpr中使用oracle::answer是好的,即使forecast的定义也是如此在h2g2_oracle的定义之后。但是,在forecast中使用h2g2_oracle时,forecast<h2g2_oracle>::answer必须完成。这对我来说很合理。 其他想法:我更加着迷的是如何将静态成员初始化为对另一个静态成员的引用(可能在不同的翻译单元中)。

@dyp about

  

有趣的是,我不确定在预测中使用它之前是否需要h2g2 :: answer的定义;应该使用它(我觉得很奇怪)。

我想我现在明白了。这也是我觉得很有趣的事实:事实上,main甚至可以移动到不同的翻译单元,它仍然有效。不知何故,链接器(简单的单词)设法在需要的地方“插入”int h2g2_oracle::_answer = 42;的正确内存地址。

1 个答案:

答案 0 :(得分:2)

简单的解决方法是内联的,当然不需要存储:

template<typename oracle>
struct forecast
{
  static const int& answer() { return h2g2_oracle::answer; }
};

它也兼容C ++ 98。