I'm using C++14 and trying to create a for each loop that prints out each string of the array. I get the error:
user.cpp:12:34: error: invalid initialization of reference of type ‘std::string& {aka std::basic_string&}’ from expression of type ‘char’
for(std::string &str : *(u->favs)){
When I change the std::string to auto in the foreach loop, it works but str becomes individual characters of the first string in the favs array. My code is as follows:
user.h
class User{
private:
public:
User(){
favs = new std::string[5]{std::string("Hello"), std::string("how"), std::string("are"), std::string("you"), std::string("?")};
}
~User(){
delete[] favs;
}
std::string lName;
std::string fName;
int age;
std::string *favs;
};
user.cpp
#include <iostream>
#include "user.h"
void create(User *u){
std::cout << "Please enter first name: ";
std::cin >> u->fName;
std::cout << "Please enter last name: ";
std::cin >> u->lName;
std::cout << "Please enter age: ";
std::cin >> u->age;
for(std::string &str : *(u->favs)){
std::cout << str << std::endl;
}
std::cout << "\n";
}
main.cpp
#include <iostream>
#include <string>
#include "user.h"
int main(){
std::string command;
User user;
std::cout << "bp1: " << user.favs->size() << std::endl;
while(true){
std::cout << "Please enter a command (Create, Update, View, Favorites, or Quit): ";
std::cin >> command;
if(command == "Create"){
create(&user);
} else if(command == "Update"){
update(&user);
} else if(command == "View"){
view(&user);
} else if(command == "Favorites"){
//favorites(&user);
} else if(command == "Quit"){
break;
} else std::cout << "Please input a valid command.\n";
}
}
When you dereference u->favs
you get a std::string&
, and range based for then starts iterating over that string
one character at a time. This is why when you auto
you see individual characters from the first string, and when you try to bind that character to a string&
you get a compilation error.
You cannot get a range based for to work with a pointer type, because it has no way of knowing how many objects your pointer points to. If you make the following changes to your code to declare favs
as a statically sized array, then your code will work.
Change your class definition to
using namespace std::string_literals; // allows use of operator""s (user defined literal)
class User
{
public:
User()
: favs{{"Hello"s, "how"s, "are"s, "you"s, "?"s}} // use operator""s
{}
// no need for a destructor definition
std::string lName;
std::string fName;
int age;
std::array<std::string, 5> favs; // statically sized array
};
If you need a dynamically sized array, then use std::vector<std::string>
instead, and your loop will still work.
If you want to use the range-based loop, there's 2 ways:
1) std::string favs[n];
range-based loop works against arrays with constant size
2) std::vector<std::string> favs
range-based loop works against objects that have implemented begin / end, and the STL containers do that.
class User{
public:
User() : favs {"Hello", "how", "are", "you", "?"} { }
std::vector<std::string> favs;
};
for(std::string& str : u->favs)
std::cout << str << std::endl;
3) If favs
will be the main array of your class... and you want to try the begin / end idea, here's how you would do it:
class User
{
public:
std::string *favs;
int favs_size;
User()
{
favs_size = 5;
favs = new string[favs_size];
}
~User() { delete[] favs; }
public:
std::string* begin() { return favs; }
std::string* end() { return favs+favs_size ; }
};
User u;
for(std::string &str : u)
std::cout << str << std::endl;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With