This question already has answers here:
uint8_t can't be printed with cout
(8 answers)
Closed 4 months ago.
#include<iostream>
#include<string>
class Person_t{
private:
uint8_t age;
public:
void introduce_myself(){
std::cout << "I am " << age << " yo" << std::endl;
}
Person_t()
: age{99}
{ };
};
int main(){
Person_t person1{};
person1.introduce_myself();
}
When the shown code is executed, the integer from the initializer list gets converted to a c. I have no explaination why, could someone please explain this to me?
<< age
age is a uint8_t, which is an alias for an underlying native type of a unsigned char. Your C++ library implements std::ostream's << overload for an unsigned char as a formatting operation for a single, lonely, character.
Simply cast it to an int.
<< static_cast<int>(age)
My program won't allow me to output these values because the "type name is not allowed" (highlighted in asterisks). What does that mean? What's wrong? I'm trying to parse this MIDI file, and it seems I need to use these data types, as the program was outputting the incorrect values (only MThd was outputting correctly, the rest were random hex values). What can I do to fix this? I'm new to coding, so sorry if this is a stupid question.
#include <iostream>
#include <fstream>
#include <stdint.h>
typedef struct MIDI_CHUNK_HEADER {
char MThd[4];
typedef uint32_t ChunckSize[4];
typedef uint16_t Format[2];
typedef uint16_t Track[2];
typedef uint16_t TimeDivision[2];
} MIDI_CHUNK_HEADER;
int main()
{
std::ifstream In_File("C:\\Users\\micah\\Documents\\Twinkle.mid", std::ios::binary | std::ios::in);
if (!In_File)
{
std::cerr << "Problem opening file!";
return 1;
}
MIDI_CHUNK_HEADER midi_chunk_header;
In_File.read((char*)&midi_chunk_header, sizeof(MIDI_CHUNK_HEADER));
std::cout << "File type is: "<< midi_chunk_header.**MThd** << std::endl;
std::cout << "Bytes to follow: " << midi_chunk_header.**ChunckSize** << std::endl;
std::cout << "MIDI Format: " << midi_chunk_header.**Format** << std::endl;
std::cout << "MIDI Track: " << midi_chunk_header.**Track** << std::endl;
std::cout << "MIDI Time Division: " << midi_chunk_header.**TimeDivision** << std::endl;
}
typedef declares an alias for a type name. It does not declare a variable. You cannot use a type name in an expression as if it was a variable name.
If you intended to declare class members, then drop the typedef. Also don't use typedef struct in C++. It has use in C, but is redundant in C++. A class can be defined directly without typedef:
struct MIDI_CHUNK_HEADER {
char MThd[4];
uint32_t ChunckSize[4];
uint16_t Format[2];
uint16_t Track[2];
uint16_t TimeDivision[2];
};
Furthermore you cannot output arrays directly with <<. It will print the address of the first array element instead, except for the case of char arrays (which will be interpreted as C style null-terminated strings). You need to loop over the individual elements and output each individually.
(Without looking at the MIDI chunk header format specification:) It seems that you don't actually want arrays at all. If you want e.g. ChunckSize to represent 4 bytes, then you want only one uint32_t (which is 32bits equaling 4 bytes already by itself), not four of them:
struct MIDI_CHUNK_HEADER {
char MThd[4];
uint32_t ChunckSize;
uint16_t Format;
uint16_t Track;
uint16_t TimeDivision;
};
Please learn the language from a good book. It would explain how everything works in a structured way and you wouldn't make mistakes such as using typedef here. Learning C++ in an unstructured way will not get you far. C++ is too unforgiving to mistakes.
The problem i am having is when i compile my code, i get an error (uninitialized local variable "optionNumber used"
I am using visual studio 2017 on a macbook air for this.
here is my code:
#include "pch.h"
#include <iostream>
int runMenu(int optionNumber) {
std::cout << "Choose an option \n";
std::cout << "1) Create Array \n";
std::cout << "2) View Array \n";
std::cout << "3) Add/Delete Values \n";
std::cin >> optionNumber;
return(optionNumber);
};
int main()
{
int optionNumber;
int optionNum;
optionNum = runMenu(optionNumber);
std::cout << optionNum;
return(0);
}
int main()
{
int optionNumber;
^^^^^^^^^^^^^^^^
Here, you've declared a local variable. You've not provided an initialiser. Therefore the local integer has an indeterminate value. If you read an indeterminate value, the behaviour of your program will be undefined.
optionNum = runMenu(optionNumber);
^^^^^^^^^^^^
Here, you copy the variable whose value is indeterminate into an argument. Therefore the behaviour of the program is undefined. Luckily, your compiler noticed this mistake and warned about it.
Most trivial solution: Initialise the variable:
int optionNumber = 42;
On the other hand, you may want to think a bit about what you've written. The value that you pass to the function runMenu is never used in the function. Whatever value is passed in will be overwritten by whatever is extracted from standard input. The argument is completely pointless. Instead of an argument, you can read the input into a local variable:
int runMenu() {
// your std::cout stuff
int optionNumber;
std::cin >> optionNumber;
Is there a C++ container that I could use or build that can contain, say, int and string and double types? The problem I'm facing is that whenever I try to populate, say, a map, vector or list with, say, the following:
int x;
string y;
double z;
I'm restricted with the format:
list<int> mycountainer;
vector<string> mycontainer;
which forces mycontainer to only consist of one type.
Before anyone suggest generics, that wouldn't work either since the standard vector and list containers that come with C++ are already generic - they can be container for any types but cannot contain multiple types.
I would like to avoid using Boost also if at all possible - I'd prefer it if there is a simple way I could code this myself.
You could use (or re-implement) boost::any and store instances of boost::any in a container. That would be the safest, since boost::any has probably dealt with much of the edge cases and complexity involved in solving this kind of problem in the general case.
If you want to do something quick and dirty, create a structure or perhaps a union containing members of all potential types along with an enumeration or other indicator of which type is 'active' in the object. Be especially careful with unions as they have some interesting properties (such as invoking undefined behavior if you read the wrong union member, only one of the members can be 'active' at a time, the one that was most recently written to).
I'm curious what you're doing that you need such a construct, though.
Well, the first question would be: Why do you think you need to store objects of different, totally unrelated types in the same container? That seems fishy to me.
If I had the need, I'd look into boost::variant or boost::any.
What you want is called a "hetrogenious container". C++ doesn't technically support them in the STL, but Boost does.
Given that, I think you'll find your answer in this question: how-do-you-make-a-heterogeneous-boostmap
You can use either structures, or classes or std::pair.
[edit]
For classes and structs:
struct XYZ {
int x;
string y;
double z;
};
std::vector<XYZ> container;
XYZ el;
el.x = 10;
el.y = "asd";
el.z = 1.123;
container.push_back(el);
For std::pair:
#include <pair>
typedef std::pair<int, std::pair<string, double> > XYZ;
std::vector<XYZ> container;
container.push_back(std::make_pair(10, std::make_pair("asd", 1111.222)));
You could use a struct that contains all three.
struct Data
{
int intVal;
std::string stringVal;
double doubleVal;
};
Then you could just declare list mycontainer<Data> and use the appropriate value, provided you know what the value type is. If not, add an addition field to the struct that tells you which of the three data types is in use.
struct Data
{
enum DATATYPE { DT_INT, DT_STRING, DT_DOUBLE } type;
int intVal;
std::string stringVal;
double doubleVal;
};
If you're worried about memory usage, you could probably use a union, though I tend to avoid using them. It might be needless paranoia on my part though.
The simplest method is of course to define a struct or class that has members of each of the types you wish to store. Josh's answer suggests Boost.Any, which will hold pretty much anything. If you want to restrict values to only those of types int, double, and std::string, then the better choice would be Boost.Variant.
If you simply don't want to use Boost, then I suggest you get over your hang-ups and use it anyway. "Not Invented Here" is a self-destructive policy. But if you can't use Boost, then you can write your own variant class instead. Andrei Alexandrescu wrote a three-part series on that (part 1, part 2, part 3) a few years ago, and its design inspired the one Boost uses.
What I have for this question is not what I hoped would work. By what I think that you would like, is a container that stores multiple value types, that you can access at will.
However, as such, a container would have to specify what value it holds, so you could have a class with 500 data types in it, with a correlating constructor for each data type, however, that would be super memory inefficient.
Here is my proposed suggestion, I have worked on for a day, And I hope it meets your criteria:
#include <iostream>
#include <vector>
using namespace std;
enum class type: unsigned int {int_t, unsigned_int_t, string_t, double_t, float_t, bool_t, unipointer_t, vector_int_t, vector_unipointer_t};//just add item types here and in the switch statement to hold more void_ps in unipointer...
class unipointer {
void* obj;//the pointer to the data. any type of pointer.
type objtype;//the object type, kept as an enum class.
struct void_p {//template magic... ;D
void* void_ptr;
template<typename T>//when object is initialized, it converts the the void* pointer to the output value.
operator T() {
return reinterpret_cast<T&>(void_ptr);
}
void_p(void* val): void_ptr(val) {};
};
public:
unipointer(void_p ptr, type ptrtype) : obj(ptr), objtype(ptrtype) {}
type get_type(void) {//Once you call this function, you know the type of data stored, and can call other functions accordingly.
return objtype;
}
template<typename T>//With a temlate, get any value through a pointer to it.
T get_ptr(void){
return reinterpret_cast<T&>(obj);
}
template<typename T>//With a temlate, get any value, as an object
T get_object(void) {
return *get_ptr<T*>();
}
void_p get_auto_pointer(void) {//get any pointer to value, can't be assigned to "auto*"!
return unipointer::void_p(obj);
}
void_p get_auto_object(void) {//get any value, can't be assigned to "auto"!
return *(void_p*)get_auto_pointer();
}
};
void process_stuff(unipointer& thing, unsigned int num_of_tabs);
int main() {
double initialization = 1.2345;
float even_another = 3.14159f;
unipointer items(new vector<unipointer>{//one thicc object instance
//Initialization examles:
unipointer(new int(-12345), type::int_t),
unipointer(new unsigned int(4'294'967'295), type::unsigned_int_t),
unipointer(new string("That is how I store my items."), type::string_t),
unipointer(&initialization, type::double_t),
unipointer(&even_another, type::float_t),
unipointer(new bool(1), type::bool_t),
unipointer(new unipointer(new unipointer(new unipointer(new string("OMG! NESTING!"), type::string_t), type::unipointer_t), type::unipointer_t), type::unipointer_t),
unipointer(new vector<int>{ 1,2,3 }, type::vector_int_t),
unipointer(new vector<unipointer>{
unipointer(new string("That is how I store my nested items."), type::string_t),
unipointer(new vector<int>{4,5,6}, type::vector_int_t),
unipointer(new string("Is your head brimming with ideas yet?"), type::string_t)
} , type::vector_unipointer_t)
}, type::vector_unipointer_t);
cout << "What is in the \"items\" unipointer:" << endl;
process_stuff(items, 1);
system("pause");
}
void process_stuff(unipointer& thing, unsigned int num_of_tabs) {
//declare variables & lamda for interpretaion methods, using variable assignment with "get auto object/pointer"
unsigned int* test = 0;
double test_2 = 0;
auto tab_to_current = [num_of_tabs]() {
for (unsigned int i = 0; i < num_of_tabs; ++i) {
cout << "\t";
}
};
//format the thing.
tab_to_current();
//look through and do stuff
switch (thing.get_type()) {//just add item types here and in the enum class to hold more void_ps in unipointer...
case type::int_t:
cout << "The integer: " << *thing.get_ptr<int*>() << "." << endl;//one way of getting object back from class
break;
case type::string_t:
cout << "The string: \"" << thing.get_object<string>() << "\"." << endl;//another way
break;
case type::unsigned_int_t:
test = thing.get_auto_pointer();//another way
cout << "The unsigned integer: " << *test << "." << endl;//don't forget to de-reference it!
delete test;
break;
case type::double_t:
test_2 = thing.get_auto_object();
cout << "The double: " << test_2 << "." << endl;//even another way!
break;
case type::float_t:
cout << "The float: " << float(thing.get_auto_object()) << "." << endl;//even another way!
break;
case type::bool_t:
cout << "The boolean: " << *(bool*)thing.get_auto_pointer() << "." << endl;//even another way!
break;
case type::unipointer_t:
cout << "A unipointer, and in it:" << endl;
process_stuff(*&thing.get_object<unipointer>(), num_of_tabs+1);
tab_to_current();
cout << "[End of unipointer]" << endl;
break;
case type::vector_int_t:
cout << "A vector of integers, and in it:" << endl;
for (unsigned int i = 0; i < thing.get_object<vector<int>>().size(); ++i) {
tab_to_current();
cout << "\tItem " << i << ": " << thing.get_object<vector<int>>().at(i) << endl;
}
tab_to_current();
cout << "[End of vector of integers]" << endl;
break;
case type::vector_unipointer_t:
cout << "A vector of unipointers, and in it:" << endl;
for (unsigned int i = 0; i < thing.get_object<vector<unipointer>>().size(); ++i) {
process_stuff(*&thing.get_object<vector<unipointer>>().at(i), num_of_tabs + 1);
}
tab_to_current();
cout << "[End of unipointer vector]" << endl;
break;
}
}
The "unipointer" class should be initialized with a pointer to any object type, and also the type of object. The class can return, through a function, your data, although it is not very safe, and could be called with the wrong type of data.
This is just an example of what could work, I sure hope that you take inspiration from it.
And, to answer your original question, you would set up a list, or vector with the following format:
vector/list:
|
|unipointer(*double)
|
|unipointer(*int)
|
|unipointer(*string)
|
...
|
end
PS: I am a beginner with objects and templates, so this might be messy. Many apoligies.
If you have a finite number of items you need to store, put them in a class or structure.
If there is no limit to the items you would need to store in this container then look at a different way of doing things because the only way of doing it is by storing them as an object, and then casting them to their own type when you need to access them.
However, if any item could potentially be in the container, then you have no way of knowing what type specific items in the container are, and therefore will not be able to cast them.
If C++ contained reflection, there would possibly be a way to do this, but C++ doesn't have reflection.