using enum for an array index in c++ - c++

#include <stdlib.h>
#include <stdio.h>
using namespace std;
void main(){
char *resolutions[] = { "720x480", "1024x600", "1280x720", "1920x1080" };
int x = 0;
enum ResMode
{
p480,
p600,
p720,
p1080
};
ResMode res = p480;
printf("\nPlease enter the resolution you wish to use now by entering a number");
printf("\n480p[0], 600p[1], 720p[2], 1080p[3]");
gets(res);
printf("\nThe resolution you have selected is %s", resolutions[res]);
}
so basically i want to be able to press 1 and have it select p600 from enum and out put it as 1024x600 in the next line. I am getting a type conversion error.
How can i fix this?

Looks like you want to associate some items with other items. Usually associations are described in lookup tables or maps.
std::map<ResMode, std::string> map_table =
{
{p480, string("720x480")},
{p600, string("1024x600")},
{p720, string("1280x720")},
{p1080, string("1920x1080")},
};
int main(void)
{
cout << map_table[p480] << "\n";
return EXIT_SUCCESS;
}
Likewise, you can map menu selections to enums.
Edit 1
std::map<unsigned int, ResMode> selection_map =
{
{0, p480}, {1, p600}, {2, p720}, {3, p1080},
};
int main(void)
{
cout << "\n"
<< "Please enter the resolution you wish to use now by entering a number\n"
<<"480p[0], 600p[1], 720p[2], 1080p[3]";
unsigned int selection = 0;
cin >> selection;
if (selection < 4)
{
Resmode resolution_index = selection_map[selection];
cout << "You chose: "
<< map_table[resolution_index]
<< "\n";
}
return EXIT_SUCCESS;
}

int's are not implicitly convertible to an enum. You will have to read in an int and then cast it yourself. Example,
int resInt;
scanf("%d", &resInt);
res = static_cast<ResMode>(resInt);//Note that this does not do bound checking.

You can use "scanf" instead of "gets", something like this:
scanf("%d",&res); // I recommend use scanf_s
Or the iostream library with std::cin. But after taking the input, always, check if the input is the correct one.

As otehrs pointed out, there is no direct way of doing this. However, there are some recipes/tricks that you can use. I modified your code as follows:
#include <stdlib.h>
#include <stdio.h>
#define SOME_ENUM(DO) \
DO(_720x480) \
DO(_1024x600) \
DO(_1280x720) \
DO(_1920x1080)
#define MAKE_ENUM(VAR) VAR,
enum class RESOLUTIONS
{
SOME_ENUM(MAKE_ENUM)
};
#define MAKE_STRINGS(VAR) #VAR,
const char* const
RESOLUTION_NAMES[] =
{
SOME_ENUM(MAKE_STRINGS)
};
const char *
GET_RESOLUTION_NAME(RESOLUTIONS type)
{
return RESOLUTION_NAMES[static_cast<int>(type)];
}
int
GET_RESOLUTION_VALUE(RESOLUTIONS type)
{
return static_cast<int>(type);
}
RESOLUTIONS
GET_RESOLUTION(int i)
{
return static_cast<RESOLUTIONS>(i);
}
using namespace std;
int main(){
printf("\nPlease enter the resolution you wish to use now by entering a number");
printf("\n480p[0], 600p[1], 720p[2], 1080p[3]");
int res_type;
cin >> res_type;
RESOLUTIONS selected_res = GET_RESOLUTION(res_type);
printf("\nThe resolution you have selected is %s\n\n", GET_RESOLUTION_NAME(selected_res));
return 0;
}
Sorry for not providing an explanation, as I have to go now. This recipe can be found here. The code works and compiles for c++11.

Related

How to output a variable stored in another variable

So here's my code at the moment:
#include <iostream>
using namespace std;
int main() {
string x = "_one";
int sound_one = 7;
int sound_two = 8;
cout << ("sound") + x;
}
However when I run the code, it outputs 'sound_one' instead of '7'. How do I get it to output the variable sound_one instead of just 'sound_one'? Also, I need it so I can change x to different things (eg '_two') so it will then output sound_two instead. Any help would be greatly appreciated.
C++ is not a reflective language in the sense that you can acquire a variable name at runtime (variable names are normally compiled out of the program). You can use std::map though to achieve your immediate aim:
#include <iostream>
#include <string>
#include <map>
int main() {
using std::literals::string_literals::operator""s;
std::string x = "_one";
std::map<std::string, int> data;
data["sound_one"] = 7;
data["sound_two"] = 8;
std::cout << data["sound"s + x];
}
Note the notation "sound"s: the suffixed s denotes a std::string user defined literal.
You can't a variable from a string in this way. A work around is to use if/switch statements until the variable name is matched and then print it:
if(x == "_one") {
cout << sound_one;
}
else if(x == "_two") {
cout << sound_two;
}
else {
cout << "no match";
}
You can't do that in C++. You can use a map as shown in another answer, but I feel like what you really need is an array:
#include <format>
#include <iostream>
int main()
{
int data[] { 7, 8 };
std::cout << std::format("data[{}] = {}\n", 0, data[0]);
}
Arrays are usually better for such simple ordered sequences.

How to transfer objects from an array of objects to another in C++?

I have an array of objects and I want to transfer the objects to another array. I've written the code bellow to do so but it did not work. It is basically a code where 52 card objects are created in one array and distributed between two arrays.Can anyone help me?
class card
{
public:
string suit;
string value;
void setValue(string v);
void setSuit(string s);
};
void card::setValue(string v)
{
value=v;
}
void card::setSuit(string s)
{
suit=s;
}
int main()
{
string suites[]={"Spades","Hearts","Diamonds","Clubs"};
string values[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
card cards[52];
int i=0;
for(int j=0;j<4;j++){
for(int k=0;k<13;k++){
cards[i].setSuit(suites[j]);
cards[i].setValue(values[k]);
i++;
}
}
card player1_cards[26];
card player2_cards[26];
for(int a=0;a<52;a++){
if(a%2==0){
player1_cards[a]=cards[a];
}
else{
player2_cards[a]=cards[a];
}
}
return 0;
}
If you want every 2nd card to be added to player1_cards and the others to be added to player2_cards you can change your for-loop to:
for(int a=1;a<26;a++) {
player1_cards[a] = cards[2*a];
player2_cards[a] = cards[2*a-1];
}
As Eljay said in the comment to your question your index went past the end of the array.
I tried to compile the code myself and it seems like the following code splits the cards in to two different arrays, althought it is not random (which you might want to add if you are doing a card game).
#include <iostream>
#include <string>
class card
{
public:
std::string suit;
std::string value;
void setValue(std::string v);
void setSuit(std::string s);
std::string printSV();
};
void card::setValue(std::string v)
{
value=v;
}
void card::setSuit(std::string s)
{
suit=s;
}
std::string card::printSV() {
return suit + ": " + value + "\n";
}
int main()
{
std::string suites[]={"Spades","Hearts","Diamonds","Clubs"};
std::string values[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
card cards[52];
int i=0;
for(int j=0;j<4;j++){
for(int k=0;k<13;k++){
cards[i].setSuit(suites[j]);
cards[i].setValue(values[k]);
i++;
}
}
card player1_cards[26];
card player2_cards[26];
for(int a=1;a<26;a++){
player1_cards[a] = cards[2*a];
player2_cards[a] = cards[2*a-1];
// prints the suite and value for each card in player1's and player2's hand.
std::cout << player1_cards[a].printSV();
std::cout << player2_cards[a].printSV();
}
return 0;
}
Outputs Suite: Value for each of the cards in cards[52].
As #Eljay notes, you are trying to access elements past the end of the arrays. If you were to use a debugger to step through your program, you would see this.
However, this is also a lesson for you to be careful of writing raw loops, with a lot of "magic-number" indices, and prefer using pre-existing patterns from the libraries (especially std::algorithm) when relevant. See this talk by Sean Parent about this general principle.
Specifically, you could have written your program as follows:
#include <range/v3/view.hpp>
#include <string>
#include <array>
#include <iostream>
struct card {
std::string suite;
std::string value;
};
std::ostream& operator<<(std::ostream& os, const card& c)
{
return os << c.value << " of " << c.suite;
}
int main()
{
using namespace ranges;
std::array suites {"Spades","Hearts","Diamonds","Clubs"};
std::array values {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
auto cards =
views::cartesian_product(suites, values) |
views::transform([](const auto& suite_and_value) -> card {
return { std::get<0>(suite_and_value), std::get<1>(suite_and_value) };
});
auto num_players { 2 };
auto player1_cards =
cards | views::stride(num_players);
auto player2_cards =
cards | views::drop(1) | views::stride(num_players);
std::cout << "Player 1 got: " << player1_cards << '\n';
std::cout << "Player 2 got: " << player2_cards << '\n';
}
in which case you don't use any loops and any index variables. This uses Eric Niebler's ranges-v3 library. See also this quick reference to understand faster what's going on in this code if you're not familiar with the terms.
See this Live on GodBolt.

How to initialize items in a range in a captureless lambda, C++

My code is below. This works, It allows me to have exactly one range in my lambda.
So I guess what my question is, is how do I achieve the same results without using
"if(LOOP > 2 && LOOP < 5){int THERANGEVALUE = 2; FUNC[THERANGEVALUE]();}"?
And instead initialize an item in my captureless lambda as being ranged instead. aka, item_2 being item_range(2,4). And then also being able to continue my lambda normally, whereas Item_3 will equate to item_5.
Thank you for any help in advance, I will gladly add more input if requested.
#include <iostream>
using namespace std;
void (*FUNC[3])(void) = { //captureless lambda.
/*ITEM_0*/[](){ cout << "x" << endl;},
/*ITEM_1*/[](){cout << "y" << endl;},
/*ITEM_2->ITEM_4*/[](){cout<<"z";}
};
/*Here the [](){code;} lambda is acting as a stand-in for void FUNC() so it shouldn't touch anything outside of its scope*/
int LOOP = 4;
int main()
{
if(LOOP > 2 && LOOP < 5){int THERANGEVALUE = 2; FUNC[THERANGEVALUE]();}
FUNC[LOOP]();
return 0;
}
Adding on to this, below is the solution I came up with after asking a friend. To my surprise it was actually a lot simpler than I expected. While I couldn't initialize each item in the lambda in a range easily, I could pass it into an array and set a range inside of the array instead. So while it's not quite what I was looking for, it's...good enough for my purposes. Thanks Jaime if you see this. Otherwise I'd use PilouPili's answer below.
#include <iostream>
using namespace std;
void (*FUNC[4])(void) = { //captureless lambda.
/*ITEM_0*/ [](){ cout << "x" << endl;},
/*ITEM_1*/ [](){cout << "y" << endl;},
/*ITEM_2->ITEM_4*/[](){cout<<"z";},
/*ITEM_5*/ [](){cout<<"z";}
};
int LOOP = 4;
int main()
{
int ARR[5]={};
for(int I = 0; I < 6;I=I+1){//handling of ranged values.
if(I>2 && I<5){ARR[I]=2;} else {ARR[I]=I;}
}
FUNC[ARR[LOOP]]();
return 0;
}
I only see to way :
either extend your function array -> That's FUNC1 in the next example
change the value given in operator [] -> That's FUNC2 in the next example
#include <iostream>
#include <vector>
using namespace std;
std::vector<void (*)(void)> init_FUNC()
{
std::vector<void (*)(void)> func(5, [](){cout<<"z";});
func[0]=[](){ cout << "x" << endl;};
func[1]=[](){ cout << "y" << endl;};
return func;
}
std::vector<void (*)(void)> FUNC1= init_FUNC();
class FUNC_MAP
{
void (*_FUNC[3])(void) = { //captureless lambda.
/*ITEM_0*/[](){ cout << "x" << endl;},
/*ITEM_1*/[](){cout << "y" << endl;},
/*ITEM_2->ITEM_4*/[](){cout<<"z";}
};
typedef void (*FUNC_MAP_OUT)(void);
public:
FUNC_MAP_OUT operator[](int i)
{
if(i>2 && i<5)
{return _FUNC[2];}
else
{return _FUNC[i];}
}
};
FUNC_MAP FUNC2;
/*Here the [](){code;} lambda is acting as a stand-in for void FUNC() so it shouldn't touch anything outside of its scope*/
int LOOP = 1;
int main()
{
FUNC1[LOOP]();
FUNC2[LOOP]();
return 0;
}

C++ Undeclared Identifier on Object creation

So I am new to c++, coming from C#. This is giving me several errors when compiling, which all seem to relate to this object declaration. Anyone able to show me the right way to do this?
I get an undeclared identifier where i declare tri(sideLength).
I have used this as a reference for object declaration, but it doesn't seem to be helping me.
Thanks.
#include <iostream> // Provides cout
#include <iomanip> // Provides setw function for setting output width
#include <cstdlib> // Provides EXIT_SUCCESS
#include <cassert> // Provides assert function
#include <stdexcept>
#include <math.h>
using namespace std; // Allows all standard library items to be used
void setup_cout_fractions(int fraction_digits)
// Precondition: fraction_digits is not negative.
// Postcondition: All double or float numbers printed to cout will now be
// rounded to the specified digits on the right of the decimal.
{
assert(fraction_digits > 0);
cout.precision(fraction_digits);
cout.setf(ios::fixed, ios::floatfield);
if (fraction_digits == 0)
cout.unsetf(ios::showpoint);
else
cout.setf(ios::showpoint);
}
int main()
{
const int MAX_SIDE_LENGTH = 6;
const int INITIAL_LENGTH = 1;
const int DIGITS = 4;
const int ARRAY_SIZE = 6;
// Set up the output for fractions and print the table headings.
setup_cout_fractions(DIGITS);
// Each iteration of the loop prints one line of the table.
for (int sideLength = 0; sideLength < MAX_SIDE_LENGTH; sideLength += 1)
{
EquilateralTriangle tri(sideLength);
//Square sq(sideLength);
//Pentagon_Reg pent(sideLength);
//Hexagon_Reg hex(sideLength);
//Heptagon_Reg hept(sideLength);
//Octagon_Reg octa(sideLength);
cout << "Type: " << tri.Name() << "has area: " << tri.Area() << " with SideLength = " << sideLength;
}
return EXIT_SUCCESS;
}
//Template
class GeometricFigure
{
public:
GeometricFigure() { }
double SideLength;
virtual double Area() { return 0; };
virtual char* Name() { return ""; };
};
class EquilateralTriangle : public GeometricFigure {
public:
EquilateralTriangle(double sideLength)
{
SideLength = sideLength;
}
char* Name() { return "Equilateral Triangle"; }
double Area() { return (sqrt(3) / 2 * pow(SideLength, 2)); }
};
In C++, the compiler reads your code from top-to-bottom, once. This is a holdover from when early C compilers only had a few kilobytes of memory to work with - C was designed so that a compiler would only need to look at a little bit of the code at a time.
Because of this, things must have been declared or defined as necessary, before you try to use them.
Move both classes somewhere before main. GeometricFigure must be before EquilateralTriangle, and EquilateralTriangle must be before main.
You would need to "declare" or tell the compiler, where to look for the EquilateralTriangle and GeometricFigure, "before" you use it first. you might want to take a look at the similar discussion at - C# declarations vs definitions

Binary Tree template, class specific function call

Ok just a heads up, this is my first question on here so i apologize if I don't include every relevant piece of info on my first go, but I'll do my best.
My problem is with a specific function I'm trying to write in main() that will print out data from nodes if their "category" matches the category that is searched for. I'm likely just fumbling with syntax as I'm still pretty new at this. To be clear, the exact problem is that all the function calls I've tried tell me *****"No instance of Overloaded function "BinTree::inOrderTraverse [with Type=CategorizedContact]" matches the argument list. argument types are: (void). Object type is BinTree***** Here's the relevant main() code:
#include <iostream>
#include <string>
#include <stdexcept> //invalid_argument
using namespace std;
#include "name.h"
#include "contact.h"
#include "address.h"
#include "BinTree.h"
#include "BinNode.h"
#include "CategorizedContact.h"
#include "Field.h"
#include "htmlfunc.h"
using namespace AddressInfo;
void printMenu();
void printByCat(CategorizedContact&, int);
int getMenuInput();
int validateMenuInput(Field input);
Field printCategoryMenu();
Field categorySelection();
int main()
{
Address tmpAddress;
Name tmpName, tmpName2;
CategorizedContact tmpContact, tmpContact2, itemToRemove;
BinTree<CategorizedContact> myBook;
Field tmpString1, categoryIn;
int menuOption = 0, node = 0, count = 0, categoryMenuOption = 0, categoryInt = 0;
CategorizedContact& tmp = tmpContact2; // I was just experimenting with trying to initialize
//a ref variable here, to make the function call work.
myBook.readFile("address.csv");
do
{
printMenu();
menuOption = getMenuInput();
switch (menuOption)
{
case 1:
cout << "\t***** Add Contact *****\n\n";
categoryIn = categorySelection(); //Prints Category menu and gets input
tmpContact.setCategory(categoryIn); //Assigns category choice to tmpContact
cin >> tmpContact; //Gets the rest of the contact info
myBook.addItem(tmpContact); //Adds contact to address book
myBook.writeFile("address.csv", '\n'); //Writes new contact to file
break;
case 2:
cout << "\n\t***** Count Contacts *****\n";
count = myBook.getNumUsed();
cout << "Number of Contacts: " << count;
cout << endl << endl;
break;
case 3:
cout << "\n\t***** Print Contacts By Category *****\n";
categoryIn = printCategoryMenu(); //Prints category menu and gets choice
if (categoryIn == "All Contacts")
myBook.printAll();
categoryInt = stoi(categoryIn); // converts to int to match required function parameters
myBook.inOrderTraverse(printByCat(tmp, categoryInt));
break;
That last line before the break; is the function call I'm struggling with.
Here's it's declaration:
void printByCat(CategorizedContact& tmp, int categoryInt)
{
int count = 1;
switch (categoryInt)
{
case 65:
if (tmp.getCategory() == "Business")
cout << count << ". " << tmp << endl;
break;
default:
cout << "Error" << endl;
break;
}
}
It's unfinished, and probably not even designed correctly but I can't tell until i manage to get the function call working.
Lastly here's the relevant code from my inOrderTraverse .h and .tem files pertaining to the problem.
#ifndef BINTREE_H
#define BINTREE_H
#include <cstdlib> // NULL
#include <string>
#include <iostream> // cout
#include <fstream>
#include <algorithm> // copy
#include "BinNode.h"
#include "CategorizedContact.h"
#include "Contact.h"
template <class Type>
class BinTree
{
public:
BinTree();
BinTree(const BinTree<Type>& source);
~BinTree();
BinTree<Type>& operator=(const BinTree<Type>& source);//assignment operator
int getNumUsed() const { return(used); }
void addItem(Type dataIn);
void printAll();
void writeFile(string fileName, char delimeter = '\n');
void readFile(string fileName);
void inOrderTraverse(void process(Type&, int));
void debugOn() { debug = true; }
void debugOff() { debug = false; }
private:
bool debug;
int used;
BinNode<Type>* root;
void inOrderTraverse(void process(Type&, int),
BinNode<Type>* cursor, int& count);
void write(BinNode<Type>* cursor, char delimeter,
ofstream& outFile);
void printInOrder(BinNode<Type>* cursor, int& count);
void free(BinNode<Type>* cursor);
void copyTree(BinNode<Type>* cursor);
BinNode<Type>* alloc(Type itemToAdd);
};
#include "BinTree.tem"
And just the relevant .tem portions...
template <class Type>
void BinTree<Type>::inOrderTraverse(void process(Type&, int))
{
int count = 1;
inOrderTraverse(process, root, count);
}
template <class Type>
void BinTree<Type>::inOrderTraverse(void process(Type&, int),
BinNode<Type>* cursor, int& count)
{
if (cursor != NULL)
{
// In order traverse
inOrderTraverse(process, cursor->left, count);
// PROCESS
process(cursor->data, count);
count++;
inOrderTraverse(process, cursor->right, count);
}
}
Before anyone suggests changing the InOrderTraverse(void process(Type&, int)), or the overloaded version, just Know that I'm required to implement it that way for my project.
the only freedom i have is with ***printByCat(CategorizedContact, int)****, that can be changed as long as it's still compatible with inOrderTraverse.
So as i hope u can now see, the function in main() printByCat() is meant to take in a category from the user, and then serve as an argument itself for inOrderTraverse(printByCat()). but I'm obviously making a fundamental mistake that i don't understand.
At this point any guidance would be appreciated, I'm not asking anyone to do the coding for me as i know you are against that, but I really just need to understand why the function call isn't working. I'm guessing the problem stems from my lack of experience with reference variables, but The error I'm getting seems to suggest the function printByCat() which is being taken as an argument of inOrderTraverse, does not meet the argument requirements because it's not a void function, but it is a void function.... so yea I'm a little lost. Anyways thanks for your time, and please let me know if i forgot anything.
Found out what it was, apparently I can't include the arguments of printbyCat() when using this function as an argument of inOrderTraverse(), so the function call should have simply been: myBook.inOrderTraverse(printByCat).