C++ 将类的静态常量属性传递给函数

C++ 将类的静态常量属性传递给函数,c++,arduino,arduino-c++,C++,Arduino,Arduino C++,对于arduino学校的一个项目,我在屏幕上绘制位图,我想将所述位图存储为类中的未签名字符数组 目前我是这样做的: class Actor{ public: static constexpr unsigned char sprite[8] = {0x97, 0xd5, 0xb7, 0x00, 0xe0, 0x4a, 0x44, 0x4a}; }; void setup() { Actor a; u8g2.begin(); // setup for display u8

对于arduino学校的一个项目,我在屏幕上绘制位图,我想将所述位图存储为类中的未签名字符数组

目前我是这样做的:

class Actor{
  public:
    static constexpr unsigned char sprite[8] = {0x97, 0xd5, 0xb7, 0x00, 0xe0, 0x4a, 0x44, 0x4a};
};

void setup() {
  Actor a;

  u8g2.begin(); // setup for display
  u8g2.drawXBM(10, 10, 8, 8, a.sprite); // draw bitmap to display buffer
  u8g2.sendBuffer(); // send buffer to display
}
这将导致以下错误消息:

/tmp/cc8frii8.ltrans0.ltrans.o: In function `u8g2_DrawXBM':
/home/pichler/Arduino/libraries/U8g2/src/clib/u8g2_bitmap.c:146: undefined reference to `Actor::sprite'
/home/pichler/Arduino/libraries/U8g2/src/clib/u8g2_bitmap.c:146: undefined reference to `Actor::sprite'
collect2: error: ld returned 1 exit status
exit status 1

这让我相信变量“sprite”是无法访问的。有人知道为什么会这样,以及如何正确地做吗?提前谢谢

注意,您得到的是链接器错误,而不是编译时错误。就编译而言,一切都很好,但您还没有做足够的工作来满足整个工具链。问题是,您从未给出变量的定义,并且链接器在将所有内容组合在一起时无法找到它

如果你用C++ 17编译,这个问题就会消失。所发生的情况是,当您将
a.sprite
传递给函数时,数组将衰减为指针类型(指向第一个元素),并且由于它必须有地址,因此被视为使用了odr。这意味着变量在应用程序中必须有明确的位置,因此必须显式声明(与odr使用的任何常规静态变量一样)

对于类的静态成员,如果使用odr,则必须在应用程序中的一个位置声明它们,通常在cpp文件中:

class Foo {
    static constexpr int x;
};

// Foo.cpp
#include "Foo.h"

// Give a definition so it has a single location
int Foo::x;
将此定义与应用程序的其余部分一起编译,问题就会消失


在c++17中,constexpr静态成员是隐式的“内联”变量,这意味着定义将以不会导致重复定义错误的方式放置到每个看到它的对象文件中。这类似于函数的“内联”含义。因此,仅从类声明中,它就可以为您生成定义,因此如果您使用c++17或更高版本,则不需要上面提到的.cpp文件。

注意,您得到的是链接器错误,而不是编译时错误。就编译而言,一切都很好,但您还没有做足够的工作来满足整个工具链。问题是,您从未给出变量的定义,并且链接器在将所有内容组合在一起时无法找到它

如果你用C++ 17编译,这个问题就会消失。所发生的情况是,当您将
a.sprite
传递给函数时,数组将衰减为指针类型(指向第一个元素),并且由于它必须有地址,因此被视为使用了odr。这意味着变量在应用程序中必须有明确的位置,因此必须显式声明(与odr使用的任何常规静态变量一样)

对于类的静态成员,如果使用odr,则必须在应用程序中的一个位置声明它们,通常在cpp文件中:

class Foo {
    static constexpr int x;
};

// Foo.cpp
#include "Foo.h"

// Give a definition so it has a single location
int Foo::x;
将此定义与应用程序的其余部分一起编译,问题就会消失


在c++17中,constexpr静态成员是隐式的“内联”变量,这意味着定义将以不会导致重复定义错误的方式放置到每个看到它的对象文件中。这类似于函数的“内联”含义。因此,仅从类声明中,它就可以为您生成定义,因此,如果您使用c++17或更高版本,则不需要上述.cpp文件。

无法复制问题可能是您未发布的代码中存在问题。发布代码时,代码本身没有任何问题。该错误告诉您链接器找不到sprite的(静态)实例。考虑到行号,我假设它们实际上在不同的文件(可能还有库)中?在编译u8g2_位图时,请确保链接了Actor库。是否在C++11模式下编译它并尝试获取sprite的地址?该问题已被C++17删除,因此在C++17模式下编译。令人惊讶的是,该引用显然出现在函数
u8g2\u DrawXBM
中。github repo中的第146行是
if(u8g2\u是区间(u8g2,x,y,x+w,y+h)==0)
。那是你正在使用的库吗?@molbdnilo是的,那是我使用的库。无法复制的问题可能是你的代码中没有发布。你发布的代码本身没有问题。该错误告诉您链接器找不到sprite的(静态)实例。考虑到行号,我假设它们实际上在不同的文件(可能还有库)中?在编译u8g2_位图时,请确保链接了Actor库。是否在C++11模式下编译它并尝试获取sprite的地址?该问题已被C++17删除,因此在C++17模式下编译。令人惊讶的是,该引用显然出现在函数
u8g2\u DrawXBM
中。github repo中的第146行是
if(u8g2\u是区间(u8g2,x,y,x+w,y+h)==0)
。这是你正在使用的图书馆吗?@ MalbDNILO是的,那是图书馆,我很抱歉,我对C++非常陌生,并且不太理解你的答案。为什么我需要将我的文件包含在其中?我正在为一个ARDUIO编程,所以除了一个文件之外,所有的东西都在我用在普通C++代码中的库中,你可以从实现文件(.CPP)中分离一个头文件(.HPP)。希望使用您的代码的人包括声明的标题(以允许他们的代码进行编译),他们链接您的目标代码以解析符号(提供二进制文件的定义)。如果您只有一个cpp文件,那么您不需要包含任何内容,只需在类外添加定义,以类似于我在示例中所做的方式。如果可以,也可以使用c++17.:)我不认为这会导致库中定义的函数出现问题。我希望缺少的引用是
安装程序中使用变量iis的引用。@ChrisUzdavinis@molbdnilo感谢您抽出时间回答我!我试图在类的正下方和外部添加
unsigned char Actor::sprite[8]
,但出现了以下错误:“声明冲突