0

For reasons I don't understand, I can access a constexpr array's members using hard-coded integer literals as the index, but as soon as I try to use an integer variable, it fails to compile with the error undefined reference. But aIvoryKeys is in scope, and we can see this with hard-coded values.

class KeyboardKey{
   
public:
   
   static constexpr unsigned short int aIvoryKeys[] {0,2,4,5,7,9,11};
   
   void ShowIvory(){   
      
      // Hardcoded values work:
      std::cout << "aIvoryKeys " << aIvoryKeys[0] << std::endl; // 0
      std::cout << "aIvoryKeys " << aIvoryKeys[1] << std::endl; // 2
      std::cout << "aIvoryKeys " << aIvoryKeys[2] << std::endl; // 4
      
      // FAILS: undefined reference to `KeyboardKey::aIvoryKeys'
      int j = 2;
      std::cout << "aIvoryKeys " << aIvoryKeys[j] << std::endl; 
      
      // FAILS: undefined reference to `KeyboardKey::aIvoryKeys'
      for(int i=0;i<std::size(aIvoryKeys);++i){         
         std::cout << "aIvoryKeys " << aIvoryKeys[i] << std::endl;
      }
      
   }
   
};

If static constexpr is removed from the declaration, it compiles and runs.

The question is, why does declaring an array static constexpr seem to prevent local variables from being used to access it's members? The variable is local to the function and doesn't need any runtime information. And a constexpr array should be accessible at runtime anyway (it just doesn't change).

3
  • 1
    Does this answer your question? C++ static member variable and its initialization Commented Sep 14, 2021 at 6:54
  • 1
    i < sizeof(aIvoryKeys) and aIvoryKeys[i] also makes this have undefined behavior. Use i < std::size(aIvoryKeys) instead. You could also use inline static, example Commented Sep 14, 2021 at 6:59
  • Adding inline does seem to solve the problem. But I want to understand why. What is it actually doing to fix the problem, and what is the actual problem that inline is fixing? The other answer linked above assumes the reader knows what a "translation unit" is and how one works. I think it would be good to have an answer that explains in plain English why a variable that appears to be defined in scope is considered "undefined" unless you add the word inline before it. Right now, this seems like "magic" and I want to know what's actually happening and why. Commented Sep 16, 2021 at 8:30

1 Answer 1

2

"Hardcoded values work".

In fact no, clang spots the issue Demo

In all cases, aIvoryKeys is ODR-used and so need a definition.

C++17 makes aIvoryKeys inline, and resolves that issue.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.