Tanner G
Tanner G

Reputation: 23

Undefined reference error to static constexpr data member

I'm very confused as to what is wrong here. I am getting an undefined reference error to an array I have defined the same way as two others which are not throwing errors elsewhere in the code.

undefined reference to `shift7seg::numbers'

shift7seg.cpp code showing other function using similarly defined arrays being used

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 showing definitions of arrays being used

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
    };

Dialect is C++11 I cannot for the life of me figure out what I have done wrong. Talking to the rubber duck has done nothing so far.

More of the error code is here.

more undefined references to `shift7seg::numbers' follow
collect2.exe: error: ld returned 1 exit status
exit status 1

Upvotes: 2

Views: 1955

Answers (2)

Ryan Haining
Ryan Haining

Reputation: 36882

Somewhere in your code you are ODR-using numbers but you don't have a definition for it.

Here's a simple version of your problem (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';
}

Possible solutions are

  1. compile with -std=c++17 (or later) where all static constexpr data members are implicitly inline and don't need out-of-line definitions

  2. Add an out-of-line definition in your implementation file (shift7seg.cpp) like this (wandbox):

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

Upvotes: 3

CS Pei
CS Pei

Reputation: 11047

First of all, I think the prefix is 0B in those binary literals, not B . Second of all, you need c++17 to compile it because of the static constexpr stuff.

quote

If a static data member is declared constexpr, it is implicitly inline and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated.

from https://en.cppreference.com/w/cpp/language/static

Upvotes: 0

Related Questions