C++ access static constexpr array - c++

I am trying to get some values from an array which is declared in another class. The array has a fixed length and constant elements (I will 100% never modify its values, so that's why I made it constant).
However, when I try to access the first element in the main function, I get a compilation error:
basavyr#Roberts-MacBook-Pro src % g++ -std=c++11 main.cc
Undefined symbols for architecture x86_64:
"Vectors::vec1", referenced from:
_main in main-c29f22.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1
As you can see, I'm compiling on macOS Catalina using clang (latest version).
[Q]:What could be the issue?
Thank you in advance.
Here is the code:
#include <iostream>
class Dimension
{
public:
static constexpr int dim1 = 2;
static constexpr int dim2 = 1;
};
class Vectors
{
public:
static constexpr double vec1[2] = {4.20, 6.9};
};
int main()
{
auto a = Vectors::vec1[0]; //I also tried initializing this to a value rather than just accessing it directly through the class like I did below
std::cout << a << "\n";
std::cout << Vectors::vec1[0] << "\n";
return 0;
}

You're compiling in C++11 mode; you need to provide definition for these constexpr static members at namespace scope. Note that this is not required since c++17.
If a const non-inline (since C++17) static data member or a constexpr static data member (since C++11) is odr-used, a definition at namespace scope is still required, but it cannot have an initializer. This definition is deprecated for constexpr data members (since C++17).
e.g.
class Dimension
{
public:
static constexpr int dim1 = 2;
static constexpr int dim2 = 1;
};
constexpr int Dimension::dim1;
constexpr int Dimension::dim2;
class Vectors
{
public:
static constexpr double vec1[2] = {4.20, 6.9};
};
constexpr double Vectors::vec1[2];

Related

definition of constexpr type with Intel C++ compiler

I have a class that contains a static member which is set to the class itself evaluated in a specific way. This is an example
struct A{
constexpr A(const int i):_i(i){}
int _i;
static const A One;
};
constexpr A A::One=A(1);
This code compiles and runs with gcc and clang, but if I compile with the Intel compiler icc (v19.0.4.227) (or on Godbolt with ICC19.0.1) I get
icc -std=c++17 test.cpp
test.cpp(10): error: member "A::One" (declared at line 7) was previously not declared constexpr
constexpr A A::One=A(1);
Note that I cannot initialize A::One in the struct A{} definition since the type would be incomplete.
Is there a workaround that would work with the Intel compiler?
A main that uses this would look like, if you wanted to actually run this instead of just compile.
int main()
{
std::cout << A::One._i << std::endl;
return 0;
}

Linker Error in template specialization of a class

I have a header file TimeSeries.h, which has definitions and specializations of default_value template
TimeSeries class has other methods
I included TimeSeries.h file in main.cpp
This is my header file TimeSeries.h, followed by main.cpp
template<typename>
struct default_value;
template<>
struct default_value<int> {
static constexpr int value = 0;
};
template<>
struct default_value<double> {
static constexpr double value = std::numeric_limits<double>::quiet_NaN();
};
template <typename T>
class TimeSeries
{
public:
std::vector<uint64_t> timeUsSinceMid;
std::vector<T> values;
void addValue(uint64_t time, T value)
{
timeUsSinceMid.push_back(time);
values.push_back(value);
}
TimeSeries<T> * sample(uint64_t sampleFreq, uint64_t startTime=0, uint64_t
endTime=86400*1000*1000ULL)
{
//Some code
// I essentially faked a time and a default value push
TimeSeries<T>* newSample = new TimeSeries<T>;
newSample->timeUsSinceMid.push_back(timeUsSinceMid[0]);
newSample->values.push_back(default_value<T>::value);
return newSample;
}
};
Here is main.cpp:
#include<TimeSeries.h>
int main(int argc, const char * argv[]) {
TimeSeries<double> T;
T.addValue(1, 100.0);
T.addValue(2,200.0);
T.addValue(3,300.0);
T.addValue(4,400.0);
TimeSeries<double>* newT = T.sample(2,1,6);
//cout<<*newT<<endl;
return 0;
}
This is the linker error
Undefined symbols for architecture x86_64:
"default_value<double>::value", referenced from:
TimeSeries<double>::sample(unsigned long long, unsigned long long, unsigned long long) in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Can anyone please explain why "default_value::value" is undefined?
See the answers for this question.
Using the structure of your posted code
Your template definition defines the object value, but it still needs to be declared.
Don't ask me why, I'm just copying #Pete Becker's answer from the other post (which unfortunately wasn't very detailed). All I know is that the below code now compiles:
template<>
struct default_value<double> {
static constexpr double value = std::numeric_limits<double>::quiet_NaN();
};
// EDIT: inserted line below
constexpr double default_value<double>::value;
Changing the structure a bit
Alternatively, if you don't want to have to track value declarations through a large project, you can also turn the values into in-lined methods, like so: (edit added in constexpr's; also noting that inline is not required & likely doesn't change compiler behavior)
template<>
struct default_value<int> {
// EDIT: changed value to function
static inline constexpr int value() {
return 0;
}
};
template<>
struct default_value<double> {
// EDIT: changed value to function
static inline constexpr double value() {
return std::numeric_limits<double>::quiet_NaN();
}
};
Of course, remember to change your TimeSeries::sample method to use default_value<>::value as a method.

initialize map with static member variable

I do not understand why I cannot use a public const static member of a class in the initializer list of a map (probably any container). As I understand it "MyClass::A" is an rvalue, it seems like it should be the exact same as the case where I am using "THING" which is also a static const just outside of a class.
Here is the error:
Undefined symbols for architecture x86_64:
"MyClass::A", referenced from:
_main in map-380caf.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
And here is the code:
#include <iostream>
#include <map>
#include <string>
static const int THING = 1;
class MyClass {
public:
static const int A = 1;
};
int
main()
{
int a;
typedef std::map<int, std::string> MyMap;
// compiles and works fine
a = MyClass::A;
std::cout << a << std::endl;
// compiles and works fine
MyMap other_map = { {THING, "foo"} };
std::cout << other_map.size() << std::endl;
// Does not compile
MyMap my_map = { {MyClass::A, "foo"} };
std::cout << my_map.size() << std::endl;
return 0;
}
UPDATE 1:
Using clang on OS X:
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin14.5.0
Thread model: posix
compiler flags:
clang++ map.cc -std=c++1y
Something in the map code probably tried to take the address of a reference to your int.
The class definition here:
class MyClass {
public:
static const int A = 1;
};
does not actually create any memory for A. In order to do that you have to do in the header file:
class MyClass {
public:
static const int A;
};
and in a CPP file:
const int MyClass::A = 1;
Or I guess with the newest C++ versions you can leave the = 1 in the header and just declare the storage in the CPP file with:
const int MyClass::A;

Undefined reference std::pair

One would think that this simple piece of code should compile easily:
#include <utility>
struct Q {
static const int X = 0;
};
int main() {
std::pair<int, int>(Q::X, 0);
return 0;
}
However, when I compile this with g++ using the default settings (cygwin gcc 4.5.3) it throws a linker error at me:
undefined reference to `Q::X'
I'm totally stumped here -- MSVC compiles this just fine yet my gcc does not. (MinGW also works fine.)
The linker fails to find definition of Q::X.
This is probably because std::pair<> constructor takes arguments as references to const, and Q::X is an l-value, hence it requires an external definition of Q::X to be able to refer to that.
A portable fix:
int const Q::X;
You only declare X but you must also define it, which, for static definitions must happen outside the class
struct Q {
static const int X = 0;
};
int Q::X = 0;
#Maxim Yegorushkin (Beat me to it!) Here is a relevant link that might help.
But your problem is that the int is never externally defined. If X doesn't have to be const, you can initialize it outside the struct in a similar manner. The main reason is because X is static...
struct Q {
static const int X;
};
int const Q::X = 0;
struct Q {
static int X;
};
int Q::X = 0;

why the following code compiles fine but linking shows error when use static

The following code compiles fine. but when goes to linking,
it shows following error
Undefined symbols for architecture x86_64:
"derived::counter", referenced from:
derived::getAddressCounter() in main.cpp.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
I suspect there is something wrong with the static. but not sure why. Because once I take out the static, the code links fine. But how does static plays any role in this code?
#include <iostream>
#include <string>
struct base_result { };
struct result : public base_result {
int a;
std::string b;
};
struct base {
static base_result counter;
};
struct derived: public base {
static result counter;
result * getAddressCounter(){
counter.a = 10;
counter.b = "haha";
return &counter;
}
};
int main (){
derived d;
result * ptr;
ptr = d.getAddressCounter();
ptr->a = 20;
ptr->b = "baba";
std::cout << ptr->a << std::endl;
std::cout << ptr->b << std::endl;
return 0;
}
struct base
{
static base_result counter;
};
Only declares the static member, You also need to define it once in your cpp file.
Good Read:
What is the difference between a definition and a declaration?
In contrast to member variables which get a reserved space in every created object, static variables can't just be declared, they need to be implemented/defined too.
Just add the lines
base_result base::counter;
result derived::counter;
to your code and it will compile just fine. Those lines instructs the compiler to actually reserve space to store the static variables you declared earlier.