C++ C++;类型不完整的静态constexpr字段

C++ C++;类型不完整的静态constexpr字段,c++,c++11,C++,C++11,我试图编译这段代码,但是g++抱怨ZERO的类型不完整。这是否意味着在C++中,结构不能包含一个静态CONTXPROP/COD>实例?若然,原因为何 struct Cursor { size_t row,column; static constexpr Cursor ZERO {0,0}; //error: constexpr const Cursor Cursor::ZERO has incomplete type }; 编辑:我知道当我声明ZERO时,Cursor

我试图编译这段代码,但是g++抱怨
ZERO
的类型不完整。这是否意味着在C++中,结构不能包含一个<代码>静态CONTXPROP/COD>实例?若然,原因为何

struct Cursor
{
    size_t row,column;

    static constexpr Cursor ZERO {0,0};
    //error: constexpr const Cursor Cursor::ZERO has incomplete type
};

编辑:我知道当我声明
ZERO
时,
Cursor
不能有完整的类型。我想知道的是:有没有办法让我的
ZERO
属于
Cursor
并且仍然是
constepr

不幸的是,你根本无法做到这一点

一些
静态constexpr
成员可以内联初始化:

[C++11 9.4.2/3]:
[…]可以使用
constexpr
说明符在类定义中声明文本类型的
静态
数据成员;如果是这样,其声明应指定一个大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。[……]

Cursor
是一种文字类型,因此它很重要

并且,只要您在词法命名空间范围内初始化它,将
游标
本身作为其自身类型中的
静态
数据成员使用并不是问题:

[C++11:9.4.2/2]:
在其类定义中声明的
静态
数据成员不是定义,可能是不完整的类型,而不是cv限定的void静态数据成员的定义应出现在包含成员类定义的命名空间范围中。在命名空间范围的定义中,静态数据成员的名称应使用
运算符通过其类名限定静态数据成员定义中的初始值设定项表达式在其类的范围内(3.3.7)

但您不能使用
constexpr

[C++11:7.1.5/9]:
对象声明中使用的
constepr
说明符将对象声明为
const
。此类对象应具有文字类型,并应初始化。[……]

我认为所有这些措辞都可以改进,但与此同时,我认为您必须在封闭的名称空间中将
ZERO
设为非成员

有没有办法让零属于游标,并且仍然是
constexpr

是,如果将嵌套子类计算为“属于”包含类:

struct Cursor
{
    size_t row,column;

    struct Constants;
};

struct Cursor::Constants
{
    static constexpr Cursor ZERO {0,0};
};

如果您接受函数而不是变量,则可以

struct Cursor
{
    size_t row,column;

    static constexpr Cursor ZERO() { return Cursor{0,0}; }
};
向一个类似的问题透露,这实际上是可能实现的。您只需将
constexpr
关键字与定义而不是声明放在一起:

#包括

#include)、clang()和MSVC++2017(注意IntelliSense不喜欢它,但它编译正确!)。

您能提供错误消息吗?我怀疑这是因为constepr和inline初始化。将初始化移到类声明之外。@πάνταῥεῖ 不能使用静态constexpr成员执行此操作。@πάνταῥεῖ: 不行,小家伙。谢谢你完整的回答。鉴于游标实际上是在类VGA中定义的,我将把零设为VGA的静态constexpr成员。有时我觉得某些限制非常烦人……它确实可以编译(使用C++11/14),但在这种情况下
Cursur::ZERO
不是
constexpr
。如果我在头文件
inline constexpr Cursor const Cursor::ZERO{0,0}中内联定义,我只能在C++17中使其成为
constexpr
。但是你有没有办法在C++11中使用
constexpr
?换句话说,它应该编译为
constexpr Cursor zero=Cursor::zero
.Precision,以上示例仅适用于一个翻译单元。对于多个翻译单元,您需要
inline
定义
ZERO
,如果只能从C++17获得该定义。@AlexandreA。根据编译器的不同,可以使用类模板作为实现细节。IIRC,MSVC不允许在C++11下使用这种方法,但在跨多个翻译单元的GCC上使用
-std=C++11
(当然,Ideone上的链接并不代表这一点,但我在发布之前对其进行了测试)。不确定这是否是编译器错误,但是在MSVC15的多个翻译单元中以这种方式对成员字段执行
inline constexpr
,仍然会导致多个符号链接错误。@Miral我无法在C++17标准中找到此构造是否有效,但如果无效,则应导致编译时错误,而不是链接时错误。如果定义有
inline
constexpr
,并且编译器接受了这一点,但为其生成了一个正常的(而不是linkonce/comdat)数据符号,我肯定会称之为编译器错误。
#include <iostream>
#include <array>

struct Cursor
{
    static Cursor const ZERO;
    std::size_t row, column;
};

constexpr Cursor const Cursor::ZERO{ 0, 0 };

int main(int, char**) noexcept
{
    // using the values in a template argument ensure compile-time usage
    std::array<int, Cursor::ZERO.row> row_arr{};
    std::array<int, Cursor::ZERO.column> col_arr{};
    std::cout << "rows: " << row_arr.size() << "\ncols: " << col_arr.size();
    return 0;
}