Can't access static member function C++ - c++

I have a static member of a class of type map. but whenever I try to access it I always get an error. For example
// a.h
class a {
public:
static map<string, int>m;
a() {
}
~a() {
}
};
// a.cpp
a::m['ADD']=1;
this is the error I get = "Size of array has non-integer type 'const char[4]"
I also get a weird error in the linker.

You need to define the map before you can use it:
std::map<std::string, int> a::m = std::map<std::string, int>{{"ADD", 1}};
This will initialize it to a map holding one element with key std::string("ADD") and value 1.
Note also, use double quotes for string literals.

Compiler error: You are using single-quotes when you probably meant to use double quotes.
Linker error: When defining static variables of a class, you also have to define them in a cpp file somewhere. Add the following line to your cpp file:
map<string, int> a::m;

Related

Unable to create class vector of structs

I am trying to create an empty vector of structs. I will be adding elements at runtime with push_back().
The overall structure is a separate class has a vector of Resource objects, and each Resource object is supposed to have this struct vector, pipeline. I don't understand why this declaration is not being treated as a regular class variable. In Resource.cpp, the hint vscode gives me mentions something about an allocator. I neither know what that is, nor know how it applies.
Resource.h
#include <vector>
class Resource {
public:
int typeSize;
typedef struct PipelineSlot{
bool isBusy;
uint32_t busyCycle;
Instruction *occupiedBy;
} pls_t;
std::vector<pls_t> pipeline; //why doesn't this create a class variable?
static bool pushFU(Instruction* instr, int cycle, std::vector<Resource> &fuVector);
};
Resource.cpp
#include <Resource.h>
typedef struct PipelineSlot pls_t;
static bool pushFU(Instruction* instr, int cycle, std::vector<Resource> &fuVector) {
for (auto fu : fuVector) {
std::vector<pls_t> pipe = fu.pipeline; //IDE doesn't like this
if (fu.pipeline.size() > 0) {
if (fu.pipeline.back().busyCycle != cycle && fu.pipeline.size() < Resource::resourceLatency.find(fu.type)->second) {
pls_t newInstr {true, cycle, instr};
fu.pipeline.push_back(newInstr); //IDE doesn't like this
return true;
}
} else if (fu.pipeline.size() == 0) {
pls_t newInstr {true, cycle, instr};
fu.pipeline.push_back(newInstr); //IDE doesn't like this
return true;
}
}
return false;
}
Not sure if it's relevant, but IDE only has an issue with the push_back() calls, not with the other vector methods (which I also don't understand). The end goal is to have a class vector of structs that I can modify at run time. How do I achieve this?
EDIT: VSCode gives me this hint when I hover over the push_back() lines:
no instance of overloaded function "std::vector<_Tp, _Alloc>push_back [with _Tp=Resource::pls_t, Alloc=std::allocator<Resource::pls_t]" matches the argument list -- argument types are: (pls_t) -- object type is: std::vector<Resource::pls_t, std::allocator<Resource::pls_t>>
Compiler tells me this (lots of these errors):
error: ‘class Resource’ has no member named ‘pipeline’; did you mean ‘typeSize’?
if (fu.pipeline.size() > 0) { behavior
Note: I am a college student with a background in c, but am VERY new with c++.
So here's the fundamental error
class Resource
{
typedef struct PipelineSlot {
bool isBusy;
uint32_t busyCycle;
Instruction *occupiedBy;
} pls_t;
};
Because PipelineSlot is inside the Resource class the names created here are Resource::PipelineSlot and Resource::pls_t, not (as you seem to think) PipelineSlot and pls_t.
Outside of the Resource class PipelineSlot and pls_t must be qualified with Resource::. So this code would work
std::vector<Resource::pls_t> pipe = fu.pipeline;
So would moving the struct outside of the Resource class. That's probably what you should do.
But then you've confused things even further by creating a new typedef typedef struct PipelineSlot pls_t;. This is a completely different definition from the previous one, because it is given outside the Resource class, and the types declared here PipelineSlot and pls_t have no relation at all to the previously declared types.
Use:
std::vector<Resource::pls_t> pipe = fu.pipeline;

C++ Assign std::map values with enum class object

Consider following code.
In my real case scenario i have somthing like that:
typedef enum
{
vehicle,
computer,
} Article;
And that is what I'm trying to construct:
enum class status{
notPaid,
paid,
};
struct S {
status status_vehicle;
status status_computer;
std::map<Article, status> mymap =
{
{vehicle, S::status_vehicle},
{computer, S::status_computer},
};
};
int main ()
{
Article a1 = vehicle;
S::mymap.at(a1) = status::paid; // this line doesn't work
}
However, the last line (S::mymap.at(a1) = status::paid;) is not working. I've tried different approaches, using the find() function of std::map for example. I got the error "assignment of member std::pair<Article, status>::second in read only object".
Does someone know, how to do that? Also maybe how to design the whole in a better way? (the whole from the line "And that is what I'm trying to construct").
Also I would have prefer to use an unordered_map instead of a map but was not working. Thanks
Because mymap is not static.
You can do like this:
Article a1 = vehicle;
struct S mystruct;
mystruct.mymap.at(a1) = status::paid;
Or add static to your member in struct:
struct S {
status status_vehicle;
status status_computer;
static std::map<Article, status> mymap;
};
But when using static, you have to initialize mymap outside declaration of struct S and member that you can't use non-static members of struct
std::map<Article,status> S::mymap={
{vehicle,S::status_vehicle}
};
A static member is shared by all objects of the class. All static data
is initialized to zero when the first object is created, if no other
initialization is present
And logically is not good in your example
https://en.cppreference.com/w/cpp/language/static
Since myMap is non-static, it cannot be assigned as static variables are.
You can change your code like this:
int main ()
{
Article a1 = vehicle;
S ss;
ss.mymap.at(a1) = status::paid;
}

Char array initialisation in class

I am trying to unit test a C++ application that I am building and I'm having an issue initializing the array when used in a class. I've tried alot of different methods of loading this information, the only ones that work are inefficient / not suitable.
Here is the hex array that I have (randomised the parts)
0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10
And header file for my unit test:
class MessageParsingTest : public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(MessageParsingTest);
CPPUNIT_TEST(testIdentifyFirstMessageType);
CPPUNIT_TEST_SUITE_END();
public:
MessageParsingTest();
virtual ~MessageParsingTest();
void setUp();
void tearDown();
private:
void testIdentifyFirstMessageType();
void testIdentifySecondMessageType();
// data members for the hex array
unsigned char firstMessage[1500];
};
Then in my test case setUp function;
void MessageParsingTest::setUp() {
firstMessage = {0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10};
}
That it my latest failed attempt, it says its not valid during compilcation, as I expected, but at this point I was trying anything.
I've also tried things like (all in setUp function)
firstMessage << "\0x24\0x54\0x3b\0x72\0x8b\0x03\0x24\0x29\0x23\0x43\0x66\0x22\0x53\0x41\0x11\0x62\0x10";
firstMessage[1500] = "\0x24\0x54\0x3b\0x72\0x8b\0x03\0x24\0x29\0x23\0x43\0x66\0x22\0x53\0x41\0x11\0x62\0x10";
and a few other crazy ways, Does anyone know the proper way to load this data? the only way I've had it working so far is with either no data member declaration and straight up defining it and initializing in one line (but then I cant access in the test cases) or doing it one by one like firstMessage[0] = 0x24; etc.
I understand that there will be a simple, proper way of doing this and considering what the application actually does, this part should be the easiest.
You have few options:
Initialize arrays in constructor MesssageParsingTest using syntax : firstMessage{0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10}
in initializer list.
Create static const array containing your message, and either copy it to member variable using memcpy, or use static member and get rid of firstMessage member variable.
Declare const static member in .h inside class definition:
static const unsigned char kFirstMessage[];
and define + initialize it in .ccp
const unsigned char MessageParsingTest::kFirstMessage[] = "\0x24\0x54\0x3b\0x72\0x8b\0x03\0x24\0x29\0x23\0x43\0x66\0x22\0x53\0x41\0x11\0x62\0x10";
I would prefer static const member if you do not intend to modify this array later, since it makes the intention cleaner.
Here is one way to do it.
void MessageParsingTest::setUp()
{
unsigned char x[] = {0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10};
::memcpy(firstMessage, x, sizeof(x));
}
If you are using C++11, you can also initialize the firstMessage in the class member initialization list as
MessageParsingTest::MessageParsingTest() :
firstMessage{0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10},
...
You can use a temporary buffer and then copy into you member as this:
void MessageParsingTest::setUp() {
unsigned char tmp[1500] = {0x24,0x54,0x3b,0x72,0x8b,0x03,0x24,0x29,0x23,0x43,0x66,0x22,0x53,0x41,0x11,0x62,0x10};
memcpy(firstMessage, tmp, 1500);
}

Syntax error when initializing a static variable

There are two classes defined..
class Dictionary
{
public:
Dictionary();
Dictionary(int i);
// ...
};
and
class Equation
{
static Dictionary operator_list(1);
// ...
};
but the problem is, whenever I compile this, I get a weird error message
error C2059: syntax error : 'constant'
But it compiles well when I use the default constructor on operator_list.
In C++ you cannot combine declaration and initialization. When you do not specify constructor parameters of operator_list, you do not call its default constructor: you simply declare it. You need to also initialize it in the corresponding C++ file, like this:
Equation.h
class Equation {
static Dictionary operator_list;
};
Equation.cpp:
Dictionary Equation::operator_list(1);
Note the absence of static in the CPP file: it is not there by design. The compiler already knows from the declaration that operator_list is static.
Edit: You have a choice with static constant members of integral and enumerated types: you can initialize them in the CPP file as in the example above, or you can give them a value in the header. You still need to define that member in your C++ file, but you must not give it a value at the definition time.
static Dictionary operator_list(); is a function signature declaring a function returning a Dictionary and taking no arguments, that's why your compiler let you do it.
The reasons static Dictionary operator_list(1); fails is because you can't set a value of an complex type in the declaration of your classes. You need to do this elsewhere (e.g. in the .cpp )
For more information, see this post : https://stackoverflow.com/a/3792427/103916
#include <iostream>
using namespace std;
class Dictionary
{
public:
Dictionary() {}
Dictionary(int i):page(i) {}
void display() { cout << "page is " << page << endl; }
private:
int page;
};
class Equation
{
public:
static Dictionary operator_list;
};
Dictionary Equation::operator_list(1); // static members must be initialized this way...
int main()
{
Equation::operator_list.display();
}
Output is:
page is 1

Why can't I use static members, for example static structures, in my classes in VS2008?

When I write code like this in VS 2008:
.h
struct Patterns {
string ptCreate;
string ptDelete;
string ptDrop;
string ptUpdate;
string ptInsert;
string ptSelect;
};
class QueryValidate {
string query;
string pattern;
static Patterns pts;
public:
friend class Query;
QueryValidate(const string& qr, const string& ptn):
query(qr), pattern(ptn) {}
bool validate() {
boost::regex rg(pattern);
return boost::regex_match(query, rg);
}
virtual ~QueryValidate() {}
};
I then initialize my structure like this:
.cpp
string QueryValidate::pts::ptCreate = "something";
string QueryValidate::pts::ptDelete = "something";
//...
The compiler gives the following errors:
'Patterns': the symbol to the left of a '::' must be a type 'ptSelect'
: is not a member of 'QueryValidate'
What am I doing wrong? Is this a problem with Visual Studio or with my code? I know that static members except for const ones must be defined outside the class they were declared in.
You're trying to create a non-static member (ptCreate) of a static member (pts). This won't work like this.
You got two options, either use a struct initializer list for the Patterns class.
Patterns QueryValidate::pts = {"CREATE", "DELETE"}; // etc. for every string
Or, much safer (and better in my opinion), provide a constructor in Patterns and call that one.
struct Patterns {
Patterns() { /*...*/ }
/* ... */
}
On a side not, your code wouldn't work in any C++ compiler, it's not a conflict with Visual Studio things.
You can only initialize the structure as a whole, as in:
Patterns QueryValidate::pts = { "something", "something", ... };
This isn't valid C++. In the cpp file you're declaring parts of the static structure "QueryValidate::pts", but that's not allowed: you've got to declare the whole structure, like so:
Patterns QueryValidate::pts;
if you want members to be initialized, you either initialize them in another method, or add a constructor to Patterns that takes whatever initialization arguments you want.
I'm not real sure what you are trying to do here. It looks kind of like you are trying to declare and initialize each field in pts separately, rather than declare pts once as a single object. I'm really surprised VS lets you do that.
What worked for me in gcc was the following:
Patterns QueryValidate::pts;
void foo () {
QueryValidate::pts.ptCreate = "something";
QueryValidate::pts.ptDelete = "something";
}