对静态 constexpr 数据成员的未定义引用错误

Undefined reference error to static constexpr data member

提问人:Tanner G 提问时间:12/10/2020 最后编辑:Ryan HainingTanner G 更新时间:12/10/2020 访问量:1464

问:

我对这里出了什么问题感到非常困惑。 我收到一个数组的未定义引用错误,我以与其他两个数组相同的方式定义,这些数组没有在代码的其他地方抛出错误。

undefined reference to `shift7seg::numbers'

shift7seg.cpp 代码显示使用类似定义的数组的其他函数

uint8_t shift7seg::convert_char(const char& OGchar){
    uint8_t converted;
    switch (OGchar){
        case 'A':
            converted = capital[0];
            break;
        case 'h':
            converted = lower[3];
            break;
    //more cases removed for posting
    }
    return converted;
}

uint8_t shift7seg::convert_num(const uint8_t& OGnum){
   uint8_t converted;

   if(OGnum<10){
       converted = numbers[OGnum];
   }
   else{
       converted = blank;
   }
   return converted;
}

shift7seg.h 显示正在使用的数组的定义

class shift7seg{
public:
//constructor, choose pins to use as well as display size
    shift7seg(const uint8_t _dataPin,
              const uint8_t _latchPin,
              const uint8_t _clkPin,
              const uint8_t _num_digits);

    static constexpr uint8_t numbers[10] =               // 7 segment values for decimals 0..9
    {
    //TRUTH TABLE    |   0 = segment on
    //ABCDEFGH       |   1 = segment off
    B00000011,  //0  |        A
    B10011111,  //1  |      -----
    B00100101,  //2  |   F |     | B
    B00001101,  //3  |     |  G  |
    B10011001,  //4  |      -----
    B01001001,  //5  |   E |     | C
    B01000001,  //6  |     |     |
    B00011111,  //7  |      -----
    B00000001,  //8  |        D
    B00011001       //9  |
    };

    static constexpr uint8_t capital[13] =
    {
    B00010001,  //A or R, 0
    B00000001,  //B 1
    B01100011,  //C 2
    B00000011,  //D or O, 3
    B01100001,  //E 4
    B01110001,  //F 5
    B01000001,  //G 6
    B10010001,  //H 7
    B10000111,  //J 8
    B11100011,  //L 9
    B00110001,  //P 10
    B01001001,  //S 11
    B10000011  //U or V, 12
    };

    static constexpr uint8_t lower[9] =
    {
    B11000001,  //b 0
    B11100101,  //c 1
    B10000101,  //d 2
    B11010001,  //h 3
    B10011111,  //l 4
    B11010101,  //n 5
    B11000101,  //o 6
    B11110101,  //r 7
    B11000111   //u or v, 8
    };

方言是 C++11 我一辈子都无法弄清楚我做错了什么。到目前为止,与橡皮鸭交谈没有任何作用。

更多错误代码在这里。

more undefined references to `shift7seg::numbers' follow
collect2.exe: error: ld returned 1 exit status
exit status 1
C++ C++11 Arduino constexpr undefined-reference

评论

0赞 Nate Eldredge 12/10/2020
难道不必在类定义本身之外定义静态成员变量吗?
1赞 SergeyA 12/10/2020
此代码在 C++17 中应该是完全合法的。你的 C++ 方言是什么?
0赞 Tanner G 12/10/2020
看来这段代码是用 c++11 编译的,这是我在这种情况下可以使用的唯一编译器。在其他地方定义静态成员变量会是什么样子?这会在我的驱动程序.cpp中并像全局变量一样分配值吗?
0赞 paulsm4 12/10/2020
除了“constexpr”(C++ 或更高版本),我看不出有任何理由不应该在任何版本的 C++ 上编译和链接!问:也许引用“shift7seg”的一个或另一个目标文件不是用 C++11 编译的?
0赞 niets 12/10/2020
我不熟悉这种类型的错误,但我确实尝试编译它。我收到一个额外的错误:.当您将数组中的访问更改为某些常量(如 )时,代码将变得可编译,但是当您更改为 C++17 时,它也会编译。/usr/bin/ld: /tmp/cckpICDV.o: warning: relocation against '_ZN9shift7seg7numbersE' in read-only section '.text'OGnumnumbers2

答:

0赞 CS Pei 12/10/2020 #1

首先,我认为前缀在那些二进制文字中,而不是.其次,由于静态 constexpr 的东西,你需要 c++17 来编译它。0BB

报价

如果静态数据成员声明为 constexpr,则它是隐式内联的,不需要在命名空间范围内重新声明。这种不带初始值设定项的重新声明(以前需要,如上所示)仍然被允许,但已弃用。

与 https://en.cppreference.com/w/cpp/language/static 相比

评论

0赞 Tanner G 12/10/2020
这都是 arduino 的代码,所以正确的二进制文字标签是 B 我会看看我是否可以在没有 constexpr 的情况下让它工作
2赞 Ryan Haining 12/10/2020 #2

在代码的某个地方,你正在使用 ODR,但你没有定义它。numbers

这是您的问题(魔杖盒)的简单版本:

#include <iostream>
#include <cstdint>

class shift7seg {
  public:
   static constexpr std::uint8_t numbers[10] = {};
};

int main() {
  // taking the address is ODR-use
  std::cout << &shift7seg::numbers[0] << '\n';
}

可能的解决方案是

  1. 使用(或更高版本)进行编译,其中所有静态 constexpr 数据成员都是隐式联的,不需要外联定义-std=c++17

  2. 在实现文件 (shift7seg.cpp) 中添加一个行外定义,如下所示 (wandbox):

constexpr std::uint8_t shift7seg::numbers[10];

评论

1赞 Tanner G 12/10/2020
似乎这就是问题所在,添加行外定义已经消除了该错误并带来了其他错误。调试继续,谢谢