如何在命名空间作用域中前向声明一个constexpr对象?

9
在clang(trunk)中,我可以使用以下方式前向声明一个稍后将用constexpr定义的对象:
// Fwd-declarations
struct S;
extern const S s;

// (... later) definitions
struct S {};
constexpr S s {};

Gcc 4.8不喜欢这样,告诉我前向声明和定义在constexpr方面不同。 Gcc说的是真的吗,还是只是gcc的一个错误?

2个回答

5
我在C++11标准的副本中没有找到任何明确禁止在声明和定义之间不匹配的情况下使用constexpr的语言,但我确实看到语言明确禁止在extern中使用constexpr(第7.1.5节),并且我也看到需要在类级别的staticconstexpr变量中使用初始化程序。此外,由于当变量或其类型的定义不可用时constexpr的效用显着降低,所以我认为constexpr变量必须在声明时进行定义(或对于静态类成员,进行初始化)。

作为一种解决方法,也许您可以为该变量提供一个extern别名。这将允许您获取它的地址,这是我能想到的仅能通过前向声明实现的事情。例如:

// .hpp file:
struct C;
extern C const &c;

// .cpp file:
struct C {
    constexpr C() { }
};
constexpr C cc;
C const &c = cc;

顺便提一下:我知道在C++14中,他们重新审视/正在重新审视constexpr,所以Clang可能可以工作,因为它正在实现C++14的某些草案规范。


C++14 草案实现必须使用 -std=c++1y 启用;几乎没有什么方法可以无意中这样做。 - Griwes
@Griwes 我目前不使用Clang(虽然我想使用),所以我不知道,但这并不让我感到惊讶。但是,在开发C++14时,Clang可能已经在整个范围内扩展了对constexpr的支持(以兼容的方式)。我只是提出这种可能性。由于我在标准中找不到任何措辞,因此这两种实现都可以作为C++11的有效选择,或者这可能是一个标准缺陷。 - Adam H. Peterson
1
好的,听起来像是gcc的一个bug。我已经在这里提交了它(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59123)。 - Eric Niebler
1
DyP,仅仅因为“constexpr”必须在定义时使用,并不意味着你不能提前声明一个对象,只是“constexpr”不能出现在提前声明中。到目前为止,我还没有看到任何告诉我原来的代码无效的信息。 - Eric Niebler
1
@AdamH.Peterson 3.1/2:“声明就是定义,除非……它包含了extern说明符(7.1.1)……并且没有初始化程序或函数体……”constexpr对象声明需要一个初始化程序,而extern仅仅不会放弃这个要求,但extern constexpr int q = 3;仍然是有效的。 - Potatoswatter
显示剩余5条评论

4

实际上,gcc是错的,clang是正确的。上面的代码应该可以编译,在gcc 4.9中也可以。就像这个错误报告所说的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接