这段代码给了我不完整的类型错误.问题是什么?一个类不允许拥有自己的静态成员实例吗?有没有办法达到同样的效果?
struct Size
{
const unsigned int width;
const unsigned int height;
static constexpr Size big = { 480, 240 };
static constexpr Size small = { 210, 170 };
private:
Size( ) = default;
};
Run Code Online (Sandbox Code Playgroud) 我正在尝试编译此代码,但g ++抱怨ZERO
有一个不完整的类型.这是否意味着在C++中结构不能包含static constexpr
自身的实例?如果是这样,为什么?
struct Cursor
{
size_t row,column;
static constexpr Cursor ZERO {0,0};
//error: constexpr const Cursor Cursor::ZERO has incomplete type
};
Run Code Online (Sandbox Code Playgroud)
编辑:我明白,Cursor
当我申报时,不能有完整的类型ZERO
.我想知道的是:我有什么方法可以ZERO
归属Cursor
并且仍在存在constexpr
吗?
C++17§10.1.5/ 1指出:
的
constexpr
说明符将只应用于一个变量或变量模板的定义或功能或功能模板的声明.使用说明constexpr
符声明的函数或静态数据成员 隐式地是内联函数或变量(10.1.6).如果函数或函数模板的任何声明都有一个constexpr
说明符,那么它的所有声明都应该包含说明constexpr
符.
因为类似的段落已在标准中存在C++ 11(§7.1.5/ 1),这是在引述由理查德·史密斯评论,其中他争辩说,C++标准并没有要求constexpr
说明符之间匹配声明和变量的定义.在上段的最后一句明确要求constexpr
符横跨匹配功能和函数模板的声明,但并没有提及变量声明.
§10.1.5/ 9指出:
constexpr
对象声明中使用的说明符将对象声明为const
.这样的对象应具有文字类型并应初始化.在任何constexpr
变量声明中,初始化的完整表达式应为常量表达式(8.20).
当然,如果我们有一个单独的声明和定义,它们都需要匹配const
,无论constexpr
指定符是否需要匹配.
§12.2.3.2/ 2-3说:
2在其类定义中声明非内联静态数据成员不是定义,并且可能是除cv 之外的不完整类型
void
.未在类定义中内联定义的静态数据成员的定义应出现在包含成员类定义的命名空间范围内.在命名空间作用域的定义中,静态数据成员的名称应使用::运算符通过其类名限定.静态数据成员定义中的初始化表达式在其类的范围内(6.3.7).3如果非易失性非内联
const
静态数据成员具有整数或枚举类型...如果使用说明constexpr
符声明成员,则可以在没有初始化程序的命名空间范围内重新声明该成员 (此用法已弃用;请参阅D.1 ).其他静态数据成员的声明不应指定大括号或等于初始化器.
§D.1/ 1内容如下:
为了与先前的C++国际标准兼容,
constexpr
可以在类外部冗余地重新声明静态数据成员而不使用初始化程序.不推荐使用此用法.
从中我们可以收集到,如果使用说明符声明成员constexpr
,则命名空间范围定义是多余的, …
在编写我的初始问题时,如果这是可能的,我偶然发现了与定义类相同类型的静态constexpr成员的问题,这很清楚地回答了我的干净解决方案无法用C++ 11实现.
但后来我提出了这个与原始海报非常接近的代码,我希望实现:
class MyEnum
{
public:
constexpr MyEnum() : m_null(true), m_value(0) { }
constexpr MyEnum(const unsigned int v) : m_null(false), m_value(v) { }
constexpr operator unsigned int() const { return m_value; }
static constexpr const MyEnum one() { return MyEnum(1); }
private:
bool m_null;
unsigned int m_value;
};
Run Code Online (Sandbox Code Playgroud)
所以我在重述我的问题:为什么one
编译的解决方案可以像你期望的那样使用,但是下面的解决方案会给出使用不完整类的错误?
class MyEnum
{
public:
// snip...
static constexpr const MyEnum two = MyEnum(2);
static constexpr const MyEnum three = 3;
// snip...
}
Run Code Online (Sandbox Code Playgroud) 我试图基于一个整数数组创建一个简单的 LookUpTable,其思路是在编译时计算它.
试图使它可以用于我可能拥有的各种整数类型的任何其他未来表,我需要它作为模板.
所以我有一个LookUpTable.h
#ifndef LOOKUPTABLE_H
#define LOOKUPTABLE_H
#include <stdexcept> // out_of_range
template <typename T, std::size_t NUMBER_OF_ELEMENTS>
class LookUpTableIndexed
{
private:
//constexpr static std::size_t NUMBER_OF_ELEMENTS = N;
// LookUpTable
T m_lut[ NUMBER_OF_ELEMENTS ] {}; // ESSENTIAL T Default Constructor for COMPILE-TIME INTERPRETER!
public:
// Construct and Populate the LookUpTable such that;
// INDICES of values are MAPPED to the DATA values stored
constexpr LookUpTableIndexed() : m_lut {}
{
//ctor
}
// Returns the …
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个包含static constexpr
派生类型的CRTP ,因为这对于一个类是不可能的.这段代码在GCC中编译得很好,但是clang抱怨这Derived
是一个不完整的类型.哪一个是对的?
template<class T>
class Base {
public:
static constexpr T a = T(1), b = T(20);
};
class Derived : public Base<Derived> {
public:
int x;
constexpr Derived(int x) : x(x) {}
};
Run Code Online (Sandbox Code Playgroud) 我正在使用可变宽度的通信格式。处理它的结构看起来像这样:
struct Header
{
int msgType = -1, len;
Header() { len = sizeof(*this); }
};
struct A : public Header
{
int x; char y;
A() { msgType = 1; len = sizeof(*this); }
};
// Further structs B, C, ... declared along the same lines
Run Code Online (Sandbox Code Playgroud)
我想要一个constexpr static
成员Header::MAX_SIZE
,它给出任何这些派生类的最大大小,例如,这样我就可以分配一个缓冲区,保证可以容纳任何此类数据包。所以我想做类似的事情
struct Header
{
int msgType = -1, len;
constexpr static std::size_t MAX_SIZE;
Header() { len = sizeof(*this); }
};
// ... declaration of subclasses ...
inline Header::MAX_SIZE …
Run Code Online (Sandbox Code Playgroud) 我们有这样的代码:
template <typename T>
struct A {
static constexpr A a = A{};
};
template <typename T>
struct B {
T a;
};
B<A<int>> b;
Run Code Online (Sandbox Code Playgroud)
GCC 13 似乎对 L.3 感到满意,但对 clang 16 不满意。
<source>:3:21: error: constexpr variable cannot have non-literal type 'const A<int>'
static constexpr A a = A{};
^
<source>:9:4: note: in instantiation of template class 'A<int>' requested here
T a;
^
<source>:12:11: note: in instantiation of template class 'B<A<int>>' requested here
B<A<int>> b;
^
<source>:3:21: note: incomplete type …
Run Code Online (Sandbox Code Playgroud) 我有一个模板基类,期望子类将自身作为模板参数传递。
看起来有点像这样:
template<typename T>
struct Base {
constexpr Base(int x) : m_x(x) {}
private:
int m_x;
};
struct Derived : public Base<Derived>
{
static const Derived LIFE;
constexpr Derived(int x) : Base(x) {}
};
const Derived Derived::LIFE = Derived(42);
Run Code Online (Sandbox Code Playgroud)
编译并按预期工作。但是现在我想将Derived :: LIFE设为constexpr。这有可能吗?
我不能只将它的const限定符更改为constexpr,因为constexpr需要在其声明中进行初始化:
test.cpp:10:28: error: constexpr static data member ‘LIFE’ must have an initializer
static constexpr Derived LIFE;
Run Code Online (Sandbox Code Playgroud)
由于Derived是不完整的类型,因此无法在其中初始化:
test.cpp:10:45: error: invalid use of incomplete type ‘struct Derived’
static constexpr Derived LIFE = Derived(42);
Run Code Online (Sandbox Code Playgroud)
我知道,如果Derived是完整类型,则此问题将消失,但是由于与该问题无关的原因,在这种特殊情况下,我非常喜欢使用自引用模板化基类。
如果我正确地理解了此答案的最后一段,听起来似乎至少有一些讨论会在将来的某个时候更改不完整类型的处理方式,但是现在对我无济于事。
有人知道我上面的代码中有一些技巧可以推迟LIFE的初始化吗?