Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined symbols for architecture x86_64 linking constexpr std::array

I am getting the error in while linking my object files:

#include <cstdint>
#include <array>

enum SystemType : uint8_t { AC, DC, HCP, EFF };

template<SystemType TYPE> struct System;

template<> 
struct System<AC> { 
public:     
static constexpr size_t number_of_sockets = 2;  
static constexpr std::array<size_t, number_of_sockets> object_per_socket { { 12, 6 } }; 
};

I am using it as below to allocate data into a vector.

terminal->no_obj_per_system.assign(
            Sytem<AC>::object_per_socket.begin(),
            Sytem<AC>::object_per_socket.end());

I am using clang on mac Os.

like image 523
apramc Avatar asked Jun 07 '17 00:06

apramc


1 Answers

In C++14 and earlier, static data members must have an out-of-class definition in exactly one translation unit if they are odr-used; this rule still applies to constexpr members.

This question contains an example with references from the C++14 Standard.

If there is no out-of-class definition provided, and the variable is odr-used, then it is ill-formed with no diagnostic required, which explains why some people don't get a compilation error. To be on the safe side you should provide a definition, there's no harm doing so even in the case where the variable is not odr-used.

The definition would look like, (NOT in a header file):

constexpr std::array<size_t, System<AC>::number_of_sockets>  System<AC>::object_per_socket;

In C++17 there is a new feature "inline variables", which allows variables to be defined in header files with similar semantics to inline functions, i.e. you're allowed to have multiple matching definitions across translation units, and the compiler/linker will select one as needed. constexpr variables will be implicitly inline, so your original code will be correct in C++17. Recent versions of gcc and clang should accept the code with -std=c++1z flag.

like image 176
M.M Avatar answered Oct 04 '22 20:10

M.M