Templates generally are inline - you have to supply the definition with the declaration.
Global (static) data requires that there be exactly one definition of the data (but it can be declared multiple times).
So, for a class with static data, one normally declares the static in the class definition (header), and the storage as static in the implementation file (.cpp).
But what does one do for a template that needs to refer to static / global data?
Here's a bit of code to give you something somewhat concrete to consider:
// we represent in a formal manner anything that can be encoded in a MSVS format specification
// A format specification, which consists of optional and required fields, has the following form:
// %[flags][width][.precision][{h | l | ll | w | I | I32 | I64}] type
// based on https://msdn.microsoft.com/en-us/library/56e442dc.aspx
struct FormatSpec
{
enum Size {
normal,
h,
l,
ll,
w,
I,
I32,
I64
};
enum Type {
invalid,
character,
signed_integer,
unsigned_integer,
unsigned_octal,
unsigned_hex,
floating_point,
expontential_floating_point,
engineering_floating_point,
hex_double_floating_point,
pointer,
string,
z_string
};
unsigned fLeftAlign : 1;
unsigned fAlwaysSigned : 1;
unsigned fLeadingZeros : 1;
unsigned fBlankPadding : 1;
unsigned fBasePrefix : 1;
unsigned width;
unsigned precision;
Size size_;
Type type_;
};
struct FormatSpecTypeDatum
{
FormatSpec::Type id; // id
const TCHAR * symbol; // text symbol
};
FormatSpecTypeDatum kTypeSpecs[] =
{
{ FormatSpec::character, _T("c") },
{ FormatSpec::character, _T("C") },
{ FormatSpec::signed_integer, _T("d") },
{ FormatSpec::signed_integer, _T("i") },
{ FormatSpec::unsigned_octal, _T("o") },
{ FormatSpec::unsigned_integer, _T("u") },
{ FormatSpec::unsigned_hex, _T("x") },
{ FormatSpec::unsigned_hex, _T("X") },
{ FormatSpec::expontential_floating_point, _T("e") },
{ FormatSpec::expontential_floating_point, _T("E") },
{ FormatSpec::floating_point, _T("f") },
{ FormatSpec::floating_point, _T("F") },
{ FormatSpec::engineering_floating_point, _T("g") },
{ FormatSpec::engineering_floating_point, _T("G") },
{ FormatSpec::hex_double_floating_point, _T("a") },
{ FormatSpec::hex_double_floating_point, _T("A") },
{ FormatSpec::pointer, _T("p") },
{ FormatSpec::string, _T("s") },
{ FormatSpec::string, _T("S") },
{ FormatSpec::z_string, _T("Z") },
};
template <typename ctype>
bool DecodeFormatSpecType(const ctype * & format, FormatSpec & spec)
{
for (unsigned i = 0; i < countof(kTypeSpecs); ++i)
if (format[0] == kTypeSpecs[i].symbol[0])
{
spec.type_ = kTypeSpecs[i].id;
++format;
return true;
}
return false;
}
It's relatively simple - a symbolic ID to character representation lookup table.
I want to be able to use DecodeFormatSpecType<>() for char, unsigned char, wchar_t, etc.
I could remove the template from DecodeFormatSpecType() and just supply overloaded interfaces for various character types.
The main thing is that the data isn't really changing - an unsigned char 'c' and a wchar_t 'c' and a legacy char 'c' have the exact same value, regardless of the character's storage size (for core ASCII characters this is true, although there are undoubtedly some other encodings such as EDBIC where this isn't true, that's not the problem I'm attempting to solve here).
I just want to understand "how do I construct my C++ libraries so that I can access global data defined in exactly one location - which is stored as an array - and I want the accessing templated code to know the length of the global data, just like I can with normal non-templated code have a global symbol table like what I've shown in my example code by having the table and the implementation that needs its size both exist in the appropriate .cpp file"
Does that make sense?
global data + functions that need to know the exact definition but also can be presented (with an interface) this generic (to a valid domain).
A function template can use global functions and global data without any problem.
If you want to encapsulate the definition of kTypeSpecs and not have it defined in a header file, you can use couple of functions to provide access to the data.
size_t getNumberOfTypeSpecs();
// Provide read only access to the data.
FormatSpecTypeDatum const* getTypeSpecs();
and then implement DecodeFormatSpecType as
template <typename ctype>
bool DecodeFormatSpecType(const ctype * & format, FormatSpec & spec)
{
size_t num = getNumberOfTypeSpecs();
FormatSpecTypeDatum const* typeSpecs = getTypeSpecs();
for (unsigned i = 0; i < num; ++i)
if (format[0] == typeSpecs[i].symbol[0])
{
spec.type_ = typeSpecs[i].id;
++format;
return true;
}
return false;
}
The functions getNumberOfTypeSpecs and getTypeSpecs can be implemented in a .cpp file as:
// Make the data file scoped global variable.
static FormatSpecTypeDatum kTypeSpecs[] =
{
{ FormatSpec::character, _T("c") },
{ FormatSpec::character, _T("C") },
{ FormatSpec::signed_integer, _T("d") },
{ FormatSpec::signed_integer, _T("i") },
{ FormatSpec::unsigned_octal, _T("o") },
{ FormatSpec::unsigned_integer, _T("u") },
{ FormatSpec::unsigned_hex, _T("x") },
{ FormatSpec::unsigned_hex, _T("X") },
{ FormatSpec::expontential_floating_point, _T("e") },
{ FormatSpec::expontential_floating_point, _T("E") },
{ FormatSpec::floating_point, _T("f") },
{ FormatSpec::floating_point, _T("F") },
{ FormatSpec::engineering_floating_point, _T("g") },
{ FormatSpec::engineering_floating_point, _T("G") },
{ FormatSpec::hex_double_floating_point, _T("a") },
{ FormatSpec::hex_double_floating_point, _T("A") },
{ FormatSpec::pointer, _T("p") },
{ FormatSpec::string, _T("s") },
{ FormatSpec::string, _T("S") },
{ FormatSpec::z_string, _T("Z") },
};
size_t getNumberOfTypeSpecs()
{
return sizeof(kTypeSpecs)/sizeof(kTypeSpecs[0]);
}
FormatSpecTypeDatum const* getTypeSpecs()
{
return kTypeSpecs;
}
Update, in response to comment by OP
Yes, you can. The following are perfectly valid:
size_t getNumberOfTypeSpecs()
{
static constexpr size_t num = sizeof(kTypeSpecs)/sizeof(kTypeSpecs[0]);
return num;
}
constexpr size_t getNumberOfTypeSpecs()
{
return sizeof(kTypeSpecs)/sizeof(kTypeSpecs[0]);
}
Related
I have a particular case which I am trying to solve with minimal changes if possible.
one of the data is
js["key1"]["subkey2"]["subsubkey3"].push_back({1,2,3,{4,5}});
[ 1,2,3,[[4,5]] ]
Later at some stage I want to insert
{1,2,3,{4,6}}
Then it should become
[ 1,2,3,[[4,5],[4,6]] ]
How can I make this possible without making 1,2,3 value as key?
I did some playing. I didn't get the results you were looking for. Here's my code and results so far.
#include <iostream>
#include <json.hpp>
using namespace std;
using JSON = nlohmann::json;
int main() {
JSON json = JSON::object();
JSON key1JSON = JSON::object();
JSON key2JSON = JSON::object();
JSON key3JSON = JSON::array();
key3JSON.push_back( {1,2,3, {4,5} } );
key3JSON.push_back( {6} );
key2JSON["subsubkey3"] = key3JSON;
key1JSON["subkey2"] = key2JSON;
json["key1"] = key1JSON;
cout << json.dump(2) << endl;
}
Output:
{
"key1": {
"subkey2": {
"subsubkey3": [
[
1,
2,
3,
[
4,
5
]
],
[
6
]
]
}
}
}
You'll see that the first push_back pushed an array inside an array, which is probably one level deeper than you wanted, and the second one added a second array, which is also not what you want.
Which means you're probably going to have to write your own method, especially as you want to also handle uniqueness. I personally never free-format data that way you have in your example. But maybe your method would look something like:
bool contains(const JSON &json, const JSON &value) {
... this looks like fun to write.
}
void appendUnique(JSON &json, const JSON &array) {
for (JSON & thisJson: array) {
if (!contains(json, thisJson)) {
json.push_back(thisJson);
}
}
}
I modified my code like this:
void appendUnique(JSON &json, const JSON & array) {
for (const JSON & thisJSON: array) {
json.push_back(thisJSON);
}
}
...
appendUnique(key3JSON, {1,2,3, {4,5} } );
appendUnique(key3JSON, {6} );
And got this:
{
"key1": {
"subkey2": {
"subsubkey3": [
1,
2,
3,
[
4,
5
],
6
]
}
}
}
I'm not going to write the isUnique method. But I think you may have to take this to conclusion.
As per the tutorial:
Each JSON value is stored in a type called Value. A Document, representing the DOM, contains the root Value of the DOM tree.
If so, it should be possible to make a sub-document from a document.
If my JSON is:
{
"mydict": {
"inner dict": {
"val": 1,
"val2": 2
}
}
}
I'd like to be able to create a Document from the inner dictionary.
(And then follow the instructions in the FAQ for How to insert a document node into another document?)
Given the original document contains:
{
"mydict": {
"inner dict": {
"val": 1,
"val2": 2
}
}
}
You can copy the sub-document:
const char json[] = "{\"mydict\": {\"inner dict\": {\"val\": 1, \"val2\": 2}}}";
Document doc, sub; // Null
doc.Parse(json);
sub.CopyFrom(doc["mydict"], doc.GetAllocator());
You can also swap the sub-document with another:
const char json[] = "{\"mydict\": {\"inner dict\": {\"val\": 1, \"val2\": 2}}}";
Document doc, sub; // Null
doc.Parse(json);
sub.Swap(doc["mydict"]);
With some validation:
const char json[] = "{\"mydict\": {\"inner dict\": {\"val\": 1, \"val2\": 2}}}";
Document doc, sub; // Null
doc.Parse(json);
if (doc.IsObject()) {
auto it = doc.FindMember("mydict");
if (it != doc.MemberEnd() && it->value.IsObject()) {
sub.Swap(it->value);
}
}
Each will result in sub containing:
{
"inner dict": {
"val": 1,
"val2": 2
}
}
With the CopyFrom() approach, doc will contain:
{
"mydict": {
"inner dict": {
"val": 1,
"val2": 2
}
}
}
With Swap():
{
"mydict": null
}
Can someone explain to me why the following code for a unit test gives the error unreadVariable for n and k in cppcheck?
Combinations is a template class that calculates all combinations of n choose k but this should not matter here.
TEST(Combinations, ChooseOne)
{
const UINT8 n = 3;
const UINT8 k = 1;
Combinations<n, k> comb;
comb.calc();
std::vector< std::vector<UINT8> > _vui8Expect = { { 2 }, { 1 }, { 0 } };
EXPECT_THAT(comb.result, ::testing::ContainerEq(_vui8Expect));
}
I can change the code to the following and not get a cppcheck error anymore. But I do not like this, because it make the code less verbose. n, k are well defined quantities in statistics and they make it more clear in the call what is going on.
TEST(Combinations, ChooseOne)
{
Combinations<3, 1> comb;
comb.calc();
std::vector< std::vector<UINT8> > _vui8Expect = { { 2 }, { 1 }, { 0 } };
EXPECT_THAT(comb.result, ::testing::ContainerEq(_vui8Expect));
}
This is a known issue: http://trac.cppcheck.net/ticket/7542
So unless it will be fixed, the cppcheck will report this false positive.
I tried to put this in a comment, but here is a thought.
As far as I remember Google Tests is using TEST clause in a following manner:
TEST(test_case_name, test_name) {
... test body ...
}
I haven't personally encountered something similar, but in your case you have the very same name for the test case name, and the actual class you test.
To me it seems like some sort of name collision.
Have you tried renaming
TEST(Combinations, ChooseOne)
{
const UINT8 n = 3;
const UINT8 k = 1;
Combinations<n, k> comb;
comb.calc();
std::vector< std::vector<UINT8> > _vui8Expect = { { 2 }, { 1 }, { 0 } };
EXPECT_THAT(comb.result, ::testing::ContainerEq(_vui8Expect));
}
to a:
TEST(CombinationsTest, ChooseOne)
{
const UINT8 n = 3;
const UINT8 k = 1;
Combinations<n, k> comb;
comb.calc();
std::vector< std::vector<UINT8> > _vui8Expect = { { 2 }, { 1 }, { 0 } };
EXPECT_THAT(comb.result, ::testing::ContainerEq(_vui8Expect));
}
I am trying to implement the game Deal or no deal, i have two classes, Box & Player. in box is stored the vector game_box and in Player I want to store the box and the money that the player has to keep till the end of the game.
I have tried to implement it in this way. it runs correctly, without no errors, but when i try to verify if the values were stored into the setter, it just give me that the setter is empty. I really dont understand why! does anybody knows why?
class Box
{
vector<Box> game_box;
float pound_contained;
int box_number;
public:
Box(int box_number, float pound_contained);
Box();
int getbox_number();
float getpound_contained();
};
class Player :public Box
{
int player_box;
float player_money;
public:
Player();
~Player();
float getplayer_money();
int getplayer_box();
void setplayer_money(float);
void setplayer_box(int);
};
void Player::setplayer_money(float)
{
player_money = player_money;
}
void Player::setplayer_box(int)
{
player_box = player_box;
}
float Player::getplayer_money()
{
return this->player_money;
}
int Player::getplayer_box()
{
return this->player_box;
}
int main()
{
vector<Box> game_box;
srand(time(0));
int n;
Player money;
Box oper;
float myArray [22][2] = { { 0.01, 0 }, { 0.10, 0 }, { 0.50, 0 },
{ 1, 0 }, { 5, 0 }, { 10, 0 },
{ 50, 0 }, { 100, 0 }, { 250, 0 },
{ 500, 0 }, { 750, 0 }, { 1000, 0 },
{ 3000, 0 }, { 5000, 0 }, { 10000, 0 },
{ 15000, 0 }, { 20000, 0 }, { 35000, 0 },
{ 50000, 0 }, { 75000, 0 }, { 100000, 0 },
{ 250000, 0 }
};
//random assignation of pound value to the 22 boxes
for (int e = 1; e <22; e++)
{
int pos;
bool op = true;
while (op)
{
pos = rand() % 22 + 1;
if (myArray[pos][1] == 0)
{
myArray[pos][1] = 1;
op = false;
}
}
Box b(e, myArray[pos][0]); //creating the class game
game_box.push_back(b); //function of the vector to insert a data in it
}
// random assignment of a box to the player
int i = rand() % 22 + 1;
Box* boxes = &game_box[i];
cout << "Your box is going to be the box number: "<< boxes->getbox_number()<<endl;
////////////////////////////////////////////////////////////////////setter not working
money.setplayer_money(boxes->getpound_contained());
money.setplayer_box(oper.getbox_number());
cout << money.getplayer_box() << " " << money.getplayer_money() << endl << endl;
game_box.erase(game_box.begin()+i);
return 0;
}
There are not "setters" or "getters" in C++ that are distinct from other method calls. So you write them just as you would any other method.
To elaborate on the problem pointed out by #maniek, you wrote:
void Player::setplayer_money(float)
{
player_money = player_money;
}
C and C++ have the ability to specify method and function arguments without names--just types. This might seem a little strange as there is no way to access that parameter (at least not a way that is guaranteed to work in all compilers or optimization levels, you can possibly do it by messing with the stack). So what you are doing here is just setting the member player_money to itself.
(Note: If you are wondering why it allows you to specify a method argument without a name, it has a few uses...one is that not naming it suppresses warning messages that you aren't using that parameter. So it is a way of marking something as not being used at the current time, yet still required--perhaps for legacy reasons or perhaps because you might use it in the future.)
You can give a new name to the parameter that doesn't overlap with the name of the member variable:
void Player::setplayer_money(float new_player_money)
{
player_money = new_player_money;
}
That's one way of avoiding ambiguity. Because in terms of what value is in scope, the parameter will win over the member variable. So this would be another do-nothing operation, that would assign the parameter value to itself:
void Player::setplayer_money(float player_money)
{
player_money = player_money;
}
(Note: Since player_money is passed by value and not by reference, that wouldn't change the parameter's value at the calling site. In particular, how could it change the value, if you passed in a constant like 10.20.)
What #maniek suggested is that a way to disambiguate in that case is to use this->player_money when you mean the member variable and player_money when you mean the argument to the method. Another thing some people do is name their member variables specially--like start them with m_ as in m_player_money:
void Player::setplayer_money(float player_money)
{
m_player_money = player_money;
}
(Note: You can also just use an underscore prefix with no m as long as the next character is lowercase, but some people consider that too dangerous as underscores followed by capital letters are reserved for compiler internal usages.)
As a final thought--if the class name is Player then it's already implicit whose money you are setting (the player's) so you could just call it set_money. Furthermore, I'm not a fan of underscores in names (more common in C than C++) so I'd probably call it setMoney.
How about:
void Player::setplayer_money(float player_money)
{
this->player_money = player_money;
}
?
I'm not that good in English, that's why my Question is probably wrong. But I have a problem and I don't know how to solve it or if it's even possible to do.
I have 2 Structs defined:
typedef struct
{
UINT16 ScriptNumber;
std::string ScriptText;
} StepStruct;
typedef struct
{
std::string SequenceName;
std::string DisplayName;
StepStruct SequenceSteps;
} SequenceStruct;
As you can see, the first Struct is a Member of the second struct. So I want both structs to by dynamical. So I created 2 Dynamic Arrays from the Type StepStruct and 1 dynamic Array from the Type SequenceStruct.
The two dynamical Arrays for of the Type StepStructs are defined as follows:
StepStruct gsFirstSkript[] =
{
{ 1 , "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
StepStruct gsSecondSkript[] =
{
{ 48, "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
Those to Structs are of the Type StepStruct. Now I want to do the Same with a SequenceStruct Type, but I want to assign the two Arrays I already have to it under the Struct Member SequenceSteps. I mean this as follows:
SequenceStruct gsSequenceList[] =
{
{ "FirstScript", "Test One", gsFirstSkript},
{ "SecondScript", "Test Two", gsSecondSkript}
}
If I now want to Read the Member gsSequenceList, I can not access any information under the SequenceSteps Index of it! What means, that the Data is not copied! I tried it with Pointers
but had no success.
UINT16 lTestVal = gsSequenceList[0].SequenceSteps[2].ScriptNumber;
So Can I mangage that this works, and lTestVal contains the Value 45?
typedef struct
{
std::string SequenceName;
std::string DisplayName;
StepStruct* SequenceSteps;
} SequenceStruct;
This will allow the code to compile and the test fragment you've shown will work.
However this will not copy the data. If you change gsFristSkript it will change in gsSequenceList as well. If you want to make a copy of the data you can either do that explicitly, have a constructor or just use vector<>.
Here's the solution with vector:
#include <vector>
...
typedef struct{
std::string SequenceName;
std::string DisplayName;
vector<StepStruct> SequenceSteps;
} SequenceStruct;
vector<StepStruct> gsFirstSkript =
{
{ 1 , "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
vector<StepStruct> gsSecondSkript =
{
{ 48, "SkriptText One"},
{ 2 , "SkriptText Two"},
{ 45, "SkriptText Three"}
}
SequenceStruct gsSequenceList[] =
{
{ "FirstScript", "Test One", gsFirstSkript},
{ "SecondScript", "Test Two", gsSecondSkript}
}