a reference of type "std::string" (not const-qualified) cannot be initialized with a value of type "char"

Can some one please explain this error? I read about it but did not understand it enough to solve it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  string filename; 
	cout << "Enter Your Target File.. " << endl;
	getline(cin, filename); 
	string tag = "BODY"; 
	bool stripOtherTags = true; 
	string text = File(filename); 
	string all = ExtractBody(text, tag); 
	for (string& s : all) //a reference of type "std::string" (not const-qualified) cannot be initialized with a value of type "char"
	{
		if (stripOtherTags)
		{
			ExcludeTags(s); 
			cout << s << '\n'; 
		}
	}
What exactly are you trying to do?

The problem is that you're trying to process each character in your string "all" into another string. Perhaps you should be using either a char reference or just use auto instead.

1
2
3
...
for(auto& c : all)
...


What type of variable is ExcludeTags() expecting?

The range-based for loop is accessing the individual characters in the string. The individual characters in the string are not std::strings, they are chars.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>

int main()
{
   std::string str { "A string" };

   for (const char& itr : str)
   {
      std::cout << itr << ' ';
   }
   std::cout << '\n';
}

Using auto as the type in the for loop makes things easier, the compiler knows what type is needed:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>

int main()
{
   std::string str { "A string" };

   for (const auto& itr : str)
   {
      std::cout << itr << ' ';
   }
   std::cout << '\n';
}

@jib >What type of variable is ExcludeTags() expecting? string.
The error is that a foreach loop works on each character of a std::string.
It isn't clear what you are trying to accomplish, and you aren't explaining it.
Is 'all' supposed to be a single string, or a collection of strings? If the latter, then ExtractBody needs to return a vector<string> or another type of container of strings.
@Ganado it was a vector<string> but I am trying not to use vector so I put it as all[] (undefined string array)
The foreach loop is supposed to read every character and see if it contains the specified tags.
You don't seem to have produced a program/class design before starting to code and seem to be 'coding on the hoof' as you go along.

This isn't the way to produce a good, working program. Before you write one word of a program, you should first produce a program design. This is tried with sample data to ensure it's correct. When you're happy with the design, then you code the program from the design. Then you test/debug your program. If there's a coding error from the design, then the code is fixed as needed. If there is a design/algorithm issue then you go back to the design, modify it, then re-code the program from the updated design. This is repeated until you have a working correct program. When producing a program, the last thing you do is actually to write the code!
@seeplus The thing is, I'm trying to simplify it as much as possible for my comfort. As I said before I am not experienced in programming, need a lot of teaching. So this is not an extreme coding project it's fairly simple, but I have to know how to work around the 3rd party libraries to get the same result WITHOUT using them, I'm trying multiple things right now! Appreciate the advise.
First design, then code.

What 3rd party libraries are you trying to work around????
lmao he's talking about the standard library.

Kareem, if your instructor doesn't allow you to use them, then fine, but they are in no way "third-party". They are just as legitimate as string or iostream.

You can't return a C-style array from a function. You can pass an existing one and modify it.

1
2
3
4
5
6
7
8
9
10

void ExtractBody(string text, string tag, string arr[])
{

}

// ...

string arr[1000];
ExtractBody(text, tag, arr);
Last edited on
@Ganado I understand, by 3rd party libraries I don't mean vector specifically, I mean Boost and things like that. But thanks for the information anyways :D.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <iostream>
#include <string>
#include <fstream>
using namespace std; 



string File(string fileName); 
string ExtractBody(const string& text, string tag); 
void ExcludeTags(string& text);


string File(string fileName)
{
	string body; 
	char ch; 
	ifstream FILE(fileName); 
	if (!FILE)
	{
		cerr << fileName << " not found!" << endl; 
		exit(1); 
	}
	while (FILE.get(ch))
	{
		body = body + ch; 
		FILE.close(); 
		return body; 
	}
}

string ExtractBody(const string& text, string tag)
{
	string body; 
	unsigned int pos = 0, start; 
	while (true)
	{
		start = text.find("<" + tag, pos);
		if (start == string::npos) {
			start = text.find(">", start); 
			start++; 
				return body; 
		}
		pos = text.find("</" + tag, start); 
		if (pos == string::npos)
		{
			body = text.substr(start, pos - start); 
			return body; 
		}
	}
}

void ExcludeTags(string& text)
{
	unsigned int start = 0, pos; 
	while (start < text.size())
	{
		start = text.find("<", start);
		if (start == string::npos)
		{
			break;
		}
		pos = text.find(">", start); 
		if (pos == string::npos)
		{
			break;
		}
		text.erase(start, pos - start + 1); 
	}
}

int main()
{
	string filename; 
	cout << "Enter Your Target File.. " << endl;
	getline(cin, filename); 
	string tag = "BODY"; 
	bool stripOtherTags = true; 
	string text = File(filename); 
	string all = ExtractBody(text, tag);
	
	for (string& s : all)
	{
		if (stripOtherTags)
		{
			ExcludeTags(s);
			cout << s << '\n'; 
		}
	}
	


	
}

@jib >What type of variable is ExcludeTags() expecting? string.


1
2
3
4
5
6
7
8
	for (string& s : all)
	{
		if (stripOtherTags)
		{
			ExcludeTags(s);
			cout << s << '\n'; 
		}
	}

Okay, then do you realize that "s" is defined as a string but you're trying to stuff a single character into this string? Which gives this error in the online compiler:

81:19: error: invalid initialization of reference of type 'std::string& {aka std::basic_string<char>&}' from expression of type 'char'


Which is telling you that you can't initialize a std::string reference with a single character.

The foreach loop is supposed to read every character and see if it contains the specified tags.

Do you know the difference between a string and a character? What information are you trying to hold in your "tags".

Also look at this snippet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string File(string fileName)
{
	string body; 
	char ch; 
	ifstream FILE(fileName); 
	if (!FILE)
	{
		cerr << fileName << " not found!" << endl; 
		exit(1); 
	}
	while (FILE.get(ch))
	{
		body = body + ch; 
		FILE.close(); 
		return body; 
	}
}


Do you realize that your string body will only contain one character in the code provided?

I doubt that this is the desired behavior, so what exactly does your input file contain?

What exactly are you trying to return when reading that input?

Why did you abandon using std::vector?




@jib I realized that after looking deeper into the code, and I fixed it. Also, it is kind of like an xml parser but simpler, called ".sgm' file has this input:

<REUTERS ... >
<DATE>26-FEB-1987 15:01:01.79</DATE><TOPICS><D>cocoa</D></TOPICS>
<PLACES><D>el-salvador</D><D>usa</D><D>uruguay</D></PLACES><PEOPLE></PEOPLE>
<ORGS></ORGS><EXCHANGES></EXCHANGES><COMPANIES></COMPANIES><UNKNOWN> ... </UNKNOWN><TEXT> ...
<TITLE>BAHIA COCOA REVIEW</TITLE>
<DATELINE> SALVADOR, Feb 26 - </DATELINE>
<BODY>
Showers continued throughout the week in the Bahia cocoa zone, alleviating the drought since
...
...
Brazilian Cocoa Trade Commission after carnival which ends midday on February 27.
Reuter
&#3;
</BODY></TEXT>
</REUTERS>

It's an article distributed into 21 .sgm files. And all should be read together to extract top 10 frequent words without using the std::vector, it is a school project and I usually do it with a team now I'm doing it alone so I'm doing a lot of things alone. Had a really bad time this year so I apologize if I seem like I don't understand anything.
As per previous. that was answered here http://www.cplusplus.com/forum/windows/275322/ without using vector.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <iostream>
#include <string>
#include <utility>
#include <fstream>
#include <sstream>
#include <cctype>
#include <functional>
#include <algorithm>

const size_t maxwrds {500};

struct Words {
	size_t cnt {};
	std::string wrd;
};

using WrdsCnt = Words[maxwrds];

std::string tolower(const std::string& str)
{
	std::string low;
	low.reserve(str.size());

	for (const auto ch : str)
		if (!std::ispunct(ch))				// Ignore punctuation
			low += (char)std::tolower(ch);	// Make lower case

	return low;
}

size_t getwrd(const std::string& line, WrdsCnt& wc)
{
	static size_t nowrds {};
	std::istringstream iss(line);

	for (std::string wrd; iss >> wrd; ) {
		bool got {};

		for (size_t w = 0; !got && w < nowrds; ++w)
			if (wc[w].wrd == wrd) {
				++wc[w].cnt;
				got = true;
			}

		if (!got)
			if (const auto w = tolower(wrd); !w.empty()) {
				wc[nowrds].wrd = w;
				++wc[nowrds++].cnt;
			}
	}

	return nowrds;
}

int main(int argc, char* argv[])
{
	const std::string opent {"<BODY>"};
	const std::string closet {"</BODY>"};

	WrdsCnt wrdcnts;
	size_t nowrds {};

	std::cout << "Processing files - ";

	for (int a = 1; a < argc; ++a) {
		std::ifstream ifs(argv[a]);

		if (ifs) {
			std::string body;

			std::cout << argv[a] << "  ";

			for (auto [text, gotbod] {std::pair {std::string{}, false}}; std::getline(ifs, text); )
				for (size_t fnd {}, pos {}; fnd != std::string::npos; )
					if (gotbod)
						if (fnd = text.find(closet, pos); fnd != std::string::npos) {
							gotbod = false;
							body += text.substr(pos, fnd - pos);
							pos += closet.size();
							nowrds = getwrd(body, wrdcnts);
							body.clear();
						} else
							body += text.substr(pos) + " ";
					else
						if (fnd = text.find(opent, pos); fnd != std::string::npos) {
							gotbod = true;
							pos = fnd + opent.size();
						}
		} else
			std::cout << "\nCannot open file " << argv[a] << '\n';
	}

	std::sort(std::begin(wrdcnts), std::begin(wrdcnts) + nowrds, [](const auto& a, const auto& b) {return a.cnt > b.cnt; });

	std::cout << '\n';
	for (size_t top10 = 0; const auto& [cnt, wrd] : wrdcnts)
		if (top10++ < 10)
			std::cout << wrd << "  " << cnt << '\n';
		else
			break;
}


Don't forget to link with setargv.obj (as per previous post) to allow the expansion of file names. The usage would then be:


prognam file*.sgm

Last edited on
Topic archived. No new replies allowed.