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

Posted

技术标签:

【中文标题】对静态 constexpr 数据成员的未定义引用错误【英文标题】:Undefined reference error to static constexpr data member 【发布时间】:2021-03-21 04:33:43 【问题描述】:

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

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++17 中应该是完全合法的。你的 C++ 方言是什么? 看来这段代码是用 c++11 编译的,这是我在这种情况下可以使用的唯一编译器。在其他地方定义静态成员变量会是什么样子?那会在我的 driver.cpp 中并像全局变量一样分配值吗? 除了“constexpr”(C++11 或更高版本),我看不出有任何理由不应该在 ANY 版本的 C++ 上编译和链接!问:也许您引用“shift7seg”的一个或另一个目标文件不是用 C++11 编译的? 我不熟悉这种类型的错误,但我确实尝试编译它。我又遇到了一个错误:/usr/bin/ld: /tmp/cckpICDV.o: warning: relocation against '_ZN9shift7seg7numbersE' in read-only section '.text'。当您将numbers 数组中的OGnum 更改为2 等常量时,代码变得可编译,但是当您更改为C++17 时它也可以编译。 【参考方案1】:

在你的代码中的某个地方你是ODR-usingnumbers,但你没有它的定义。

这是您问题的简单版本 (wandbox):

#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';

可能的解决方案是

    使用-std=c++17(或更高版本)编译,其中所有static constexpr data members are implicitly inline 不需要外线定义

    像这样 (wandbox) 在您的实现文件 (shift7seg.cpp) 中添加一个行外定义:

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

【讨论】:

看来这是问题所在,添加离线定义已消除该错误并带来其他错误。调试继续,谢谢【参考方案2】:

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

报价

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

来自https://en.cppreference.com/w/cpp/language/static

【讨论】:

这是 arduino 的所有代码,所以正确的二进制文字标签是 B 我会看看我是否可以在没有 constexpr 的情况下让它工作

以上是关于对静态 constexpr 数据成员的未定义引用错误的主要内容,如果未能解决你的问题,请参考以下文章

对静态类成员的未定义引用

对静态类成员的未定义引用

通过添加 0 修复对静态成员变量的未定义引用

未定义的对静态constexpr char []的引用

c++中对静态变量的未定义引用

声明和定义函数静态会产生“对 function_name() 的未定义引用”