C++: How to specify array length with a static constant variable? - c++

I want to declare the length of an array member variable using a constant static variable of the class. If I do:
// A.h
#include <array>
using namespace std;
class A {
array<int,LENGTH> internalArray;
public:
const static int LENGTH;
};
// A.cpp
#include "A.h"
constexpr int A::LENGTH{10};
There is the error in A.h: "'LENGTH' was not declared in this scope", when declaring internalArray.
I find it weird because how come a class member variable, i.e. LENGTH, is out of scope inside the class? The only workaround I found was to move the initialization from A.cpp to A.h:
// A.h
#include <array>
using namespace std;
constexpr int LENGTH{10};
class A {
array<int,LENGTH> internalArray;
public:
const static int LENGTH;
};
But as I understand, first these are two different variables: the global namespace scope LENGTH and the class scope LENGTH. Also, declaring a variable in .h (outside class A) will create an independent LENGTH object in every translation unit where the header is included.
Is there a way to specify the length of the array with a static class-scoped variable?

Try this:
#include <array>
class A {
public:
static const size_t LENGTH = 12;
private:
std::array<int,LENGTH> internalArray;
};
int main(){
A a;
}
You can declare the value of LENGTH right in your class header, no need to have it be a separate global variable or for it to live in the cpp file.
Use the size_t type, since that is what the std::array template expects.
If that public/private arrangement is bad for you, know that you can include multiple public/private indicators in the class header.

Related

Initialize with global variables in c++

I've tried to read the thread below about creating global variables that can be used between multiple files but it will not work.
Global Variable within Multiple Files
variable.h
extern const int variable1;
file1.h
class fileOne{
private:
fileTwo ft[variable1];
public:
//some functions...
};
file2.h
class fileTwo{
private:
//some variables
public:
//some functions
};
main.cpp
int main(){
int variable1 = 2;
fileOne fo;
}
When I run this, the compiler says the following:
error: array bound is not an integer constant before ']' token
Is it possible to declare a global variable and use it in the manner above?
Also: Is this an array? fileTwo ft[variable1]; Is fileTwo a class?
A fixed-sized array needs to have its size specified at compile-time, which means only a compile-time constant can be used. You can't use an externed variable for the size of the array, even if it is declared as const, as the compiler simply doesn't know the actual value of the variable since it is in another translation unit.
Also, in main.cpp, you can't declare the extern'ed variable as a local variable, it needs to be in global scope instead.
For what you are trying to do, there is no reason to use extern at all. Just declare variable1 with a constant value directly in variable.h, and then #include that file where needed, eg:
variable.h:
#ifndef VARIABLE_H
#define VARIABLE_H
static const int variable1 = 2;
#endif
file1.h:
#ifndef FILE1_H
#define FILE1_H
#include "file2.h"
#include "variable.h"
class fileOne{
private:
fileTwo ft[variable1];
public:
//some functions...
};
#endif
file2.h:
#ifndef FILE2_H
#define FILE2_H
class fileTwo{
private:
//some variables
public:
//some functions
};
#endif
main.cpp:
#include "file1.h"
int main(){
fileOne fo;
}
To define an array you need to specify the actual size of the array and the size must be something the compiler can turn into a constant. Since variable1 can't be turned into a constant, the compiler issues the error.
What you can do is something like the following.
file1.h
class fileOne{
private:
fileTwo ft[variable1];
public:
//some functions...
};
file2.h
class fileTwo{
private:
//some variables
public:
//some functions
};
main.cpp
static const int variable1 = 2; // const int for the size of the ft array of class fileOne
#include "file2.h" // class fileTwo definition is needed for class fileOne
#include "file1.h" // class fileOne has a dependency on class fileTwo
int main(){
fileOne fo; // define a fileOne object named fo
// do more stuff
}
Is it possible to declare a global variable and use it in the manner above?
Yes, but like Remy pointed out, you would need to move this variable to a header file that will be #included from file1.h
Also: Is this an array? fileTwo ft[variable1];
Yes, this is called a C-array. The C++ standard library also has C++ arrays (i.e. fixed size) using std::array<type, size>, which are much more convenient and safe to use, as well as containers like vector, list, etc.
If you want to use a C++ array, you can declare it this way for you case:
#include <array>
std::array ft<fileTwo, variable1>;

How to pass a dynamic array of structs to a member function?

I am wondering how I can pass a dynamically allocated array of structures from the main function to a member function of a class. I don't necessarily need to change its values in the member function, just print it.
If I do it like I would with an integer array in the following code snippet, I get that MyStruct is not defined in the MyClass.h and MyClass.cpp files. (Which makes sense)
If I include main.cpp in MyClass.h I get a lot of weird errors. Another idea was prepending struct in the member function parameter, but that lead to other errors as well.
I need to declare the struct array outside of the class, not as a member, and I cannot use STL containers.
main.cpp:
#include "MyClass.h"
int main()
{
MyClass my_class;
struct MyStruct
{
int a;
int b;
};
MyStruct* struct_array = new MyStruct[4];
// Fill struct array with values...
my_class.printStructArray(struct_array);
}
MyClass.h:
#include <iostream>
class MyClass
{
// ...
void printStructArray(MyStruct* struct_array);
};
MyClass.cpp:
#include "MyClass.h"
void MyClass::printStructArray(MyStruct* struct_array)
{
std::cout << struct_array[0].a << struct_array[0].b;
// ...
}
Just move the struct definition into MyClass.h or it's own separate header file:
MyClass.h
#include <iostream>
struct MyStruct {
int a, b;
};
class MyClass {
// ...
void printStructArray(MyStruct* struct_array);
};

Why is the static variable initialized with redeclaration of static variable outside the class? Can't we just initialize it instead of redeclaring it?

#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
}
// Initialize static member of class Box
int Box::objectCount = 0;
It seems that you mix up the declaration and the definition of a variable.
The declaration just tells the compiler a name.
So in your case:
class Box
{
public:
static int objectCount;
};
This just tells the compiler that there is a variable with the name objectCount.
But now you still need a definition.
int Box::objectCount = 0;
Simplified the definition is what the linker needs.
So as a simple rule static member variables must be declared in the class and then defined outside of it.

member cannot be defined in the current scope

I am currently doing a checker for the top level domains of email addresses. In order to check, I am comparing it to a list that is a text file. I want to import the list into a static map container. However, when I try to instantiate it, it says that it cannot be defined in the current scope. Why is that?
This is some my header file:
class TldPart {
public:
static void LoadTlds();
private:
static map<string,bool> Tld;
}
Here is the implementation in the cpp:
void TldPart::LoadTlds()
{
map<string,bool> Tld;
...
}
It is telling me that ValidTld cannot be defined in the LoadTlds function.
Static members of a class exist outside of an object. You should define and initialize static member outside of the class.
Here we define and initialize a static class member:
header-file:
#pragma once
#include <map>
#include <string>
class TldPart {
public:
static void LoadTlds();
private:
static std::map<std::string, bool> tld;
};
your cpp-file:
#include "external.h"
std::map<std::string,bool> TldPart::tld;
void TldPart::LoadTlds()
{
tld.insert(std::make_pair("XX", true));
}
And don't forget semicolon at the end of the class.
EDIT: You can provide in-class initializers for static members of const integral type or static members that are constexprs and has literal type.

How to use static members as template arguments?

I have the following code structure:
myClass.h
class myClass
{
public:
void DoSomething(void);
};
myClass.cpp
#include myClass.h
static const unsigned length = 5;
static myArray<float, length> arrayX;
void myClass::DoSomething(void)
{
// does something using length and array X
}
Now I want to convert the static variable defined at the file scope to be static members of the class. I do the following;
myClass.h
class myClass
{
static const unsigned length;
static myArray<float,length> arrayX;
public:
void DoSomething(void);
};
myClass.cpp
#include myClass.h
const unsigned myClass::length = 5;
myArray<float, length> myClass::arrayX;
void myClass::DoSomething(void)
{
// does something using length and array X
}
However, I get an error:
C2975: 'Length' : invalid template argument for 'myArray', expected compile-time constant expression myClass.h
I do understand I get this error because length is not initialized in the header file yet. How can I get around this?
It needs to be a constant expression, so the best you can do is move = 5 to the header.
However, I was wondering if there is a way to get around this.
Look at your code again. That myArray<float,length> is declared as a class data member in the header.
In order for the compiler to know what myClass is, it must know the full definition of that data member. But the full definition of myArray<float,length> in turn requires length to be known, because without its template arguments, myArray is not a type, but a template, and data members must be types, not class templates.
From this it's clear that, in order to have a myArray instance as a class member, the length must be known when the class is compiled, myArray is to be a member of.
Have you tried:
myArray<float, myClass::length> myClass::arrayX;
^^^^^^^^^^
You may also need to change header:
class myClass
{
static const unsigned length = 5;
and change definition of myClass::length in .cpp to not contain "= 5" (or remove it completly).