Sign in to follow this  
Jesbass

Conversion of std::basic_string to std::string?

Recommended Posts

Jesbass    122
I'm calling a function that requires a std::string as its first parameter, but I'm passing it a std::basic_string:
Quote:
CINIParser parser(_pcIniFileName); Int32 iStringLength = static_cast<Int32>(_strStringName.length()); for(int i = 0; i < iStringLength; i++) { std::basic_string <char>::reference strCurrentLetter = _strStringName[i]; Int32 iStartX; Int32 iStopX; Int32 iStartY; Int32 iStopY; parser.GetIntValue(strCurrentLetter, "frame", iStartX); parser.GetIntValue(strCurrentLetter, "frame", iStopX); parser.GetIntValue(strCurrentLetter, "frame", iStartY); parser.GetIntValue(strCurrentLetter, "frame", iStopY); }
The errors I am receiving are for the last four lines of code, (beginning with parser.GetIntValue):
Quote:
e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(71): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string' with [ _Ty=char ] e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(72): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string' with [ _Ty=char ] e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(73): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string' with [ _Ty=char ] e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(74): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string' with [ _Ty=char ]
1) Is there a simple method to convert the std::basic_string to a std::string? I have tried both static_cast and reinterpret_cast, but to no avail. 2) Even better, is there a std::string method for finding a particular variable within a string, such as what I am using the std::basic_string line of code for:
Quote:
std::basic_string <char>::reference strCurrentLetter = _strStringName[i];
That way, I wouldn't need to worry about any conversion problems! :)

Share this post


Link to post
Share on other sites
RDragon1    1205
Your problem is not "I'm calling a function that requires a std::string as its first parameter, but I'm passing it a std::basic_string".

Your problem is that your function requires a std::string, but you're passing it a std::allocator<char>::value_type, which is a probably a typedef for just 'char'.

I have no idea why you are using basic_string. std::string is usually a typedef of std::basic_string<char>, so it's the -same thing-.

Where did that Int32 come from?

Why don't you just try this:

char& letter = some_string[i];
parser.GetIntValue( letter, "frame", iStartX );
//... etc



"finding a particular variable within a string" <-- what do you mean? There are no 'variables within a string', it's just a collection of characters. If you want to extract one character, you can use operator[] as you did, or you can iterate over the string (better), or you can use std::for_each (even better)

Share this post


Link to post
Share on other sites
Jesbass    122
Quote:
Original post by RDragon1I have no idea why you are using basic_string. std::string is usually a typedef of std::basic_string<char>, so it's the -same thing-.


I'm using basic_string because it works. I didn't realise it was effectively a char.

Quote:
Where did that Int32 come from?


I'm not sure which one you're referring to, as there are a few. Can you be more specific?

Quote:
Why don't you just try this:

char& letter = some_string[i];
parser.GetIntValue( letter, "frame", iStartX );
//... etc


I tried that, but that brings me back to requiring a conversion from char to std::string. Do you have any recommendations as to how to do that? static_cast and reinterpret_cast don't seem to do the trick.

Quote:
"finding a particular variable within a string" <-- what do you mean? There are no 'variables within a string', it's just a collection of characters. If you want to extract one character, you can use operator[] as you did, or you can iterate over the string (better), or you can use std::for_each (even better)


Sorry, I meant characters, not variables. How would I iterate or apply std::for_each in this situation? Does that mean I'd need to implement a new function that I call each time within the loop?

Share this post


Link to post
Share on other sites
Enigma    1410
Quote:
Original post by Jesbass
I'm using basic_string because it works. I didn't realise it was effectively a char.

It's not. basic_string is a class template. basic_string< char > is an instantiation of that template for ansi-style strings. Because basic_string has default template parameters basic_string< char > is shorthand for basic_string< char, char_traits< char >, allocator< char > >. string on the otherhand is a direct typedef of basic_string< char, char_traits< char >, allocator< char > >. So string and basic_string< char > are exactly the same type and can even be used interchangeably. You should prefer to use string, since this is most familiar to people and shorter to type.

Quote:
I tried that, but that brings me back to requiring a conversion from char to std::string. Do you have any recommendations as to how to do that? static_cast and reinterpret_cast don't seem to do the trick.

The problem is that you are trying to pass a char to a function that expects a string. You are almost certainly misusing the function. What exactly does parser.GetIntValue do?

Quote:
Sorry, I meant characters, not variables. How would I iterate or apply std::for_each in this situation? Does that mean I'd need to implement a new function that I call each time within the loop?

I'm not sure if it even makes sense to iterate over the characters. Sort out the previous problem first.

Enigma

Share this post


Link to post
Share on other sites
Zahlman    1682

std::basic_string <char>::reference strCurrentLetter = _strStringName[e];


As mentioned, std::basic_string<char> is the exact same thing as std::string. What you therefore have is std::string::reference, i.e. the 'reference' typedef *provided by* the std::string class. That is not a reference to a std::string (that would be spelled 'std::string&'), but instead what the type happens to be - a reference to a char, i.e. an *element* of the string. That is consistent with the illustrated indexing: "_strStringName[e]" will yield a single character of the string.

I think the problem here is logical: Iteration over the characters of the string doesn't make sense here. You are effectively asking the function to parse four numbers out of each letter - how's that going to work? What exactly is the string supposed to contain in terms of these numbers, and what do you want to do with them?

Also, please show the CINIParser::GetIntValue() function, assuming it is also your code. It appears to have a much clumsier interface than what is required.

Share this post


Link to post
Share on other sites
Jesbass    122
Thanks for the interest, guys. I appreciate you all trying to help. :)

Quote:
Original post by Enigma
The problem is that you are trying to pass a char to a function that expects a string. You are almost certainly misusing the function. What exactly does parser.GetIntValue do?


Yeah, I realise that is my problem, which is why I was trying to find a std::string function that performs the same task, (i.e. locating a specific character within a string).

parser.GetIntValue is part of my .ini parser - it opens a .ini file and retrieves an int value. Which int value it returns is dependent on the first two variables, which act as a key to direct the parser to the correct location within the .ini parser.

Quote:
Original post by Enigma
I'm not sure if it even makes sense to iterate over the characters. Sort out the previous problem first.


That was RDragon's suggestion, not mine. ;) I'm happy to let that suggestion slide if it means I can get around this problem.

Quote:
Original post by Conner McCloud
std::basic_string <char>::reference is a reference to char, not a reference to std::basic_string<char>. From there, the solution to your problem should be fairly obvious.


Hehe, not to me it isn't! :P If it were obvious, I probably would have sorted it out by now. I still find myself either wanting to convert a char into a std::string somehow, or finding a std::string function that will perform the same action.

Quote:
Original post by Zahlman
I think the problem here is logical: Iteration over the characters of the string doesn't make sense here. You are effectively asking the function to parse four numbers out of each letter - how's that going to work? What exactly is the string supposed to contain in terms of these numbers, and what do you want to do with them?


Each letter is a key to a particular location within a .ini file. Each letter of the alphabet, (this is for drawing fonts from a texture), has four numbers, effectively indicating the (startx,starty) and (stopx,stopy) parameters of a rectangle. Each rectangle will hopefully then be placed onto the screen as a texture, meaning the entire string gets written onto the screen.

Quote:
Original post by Zahlman
Also, please show the CINIParser::GetIntValue() function, assuming it is also your code. It appears to have a much clumsier interface than what is required.


Sure. :)

bool
CINIParser::GetIntValue(std::string _strBlock, std::string _strKey, Int32& _iValue)
{
std::string strMyKey;

strMyKey = _strBlock + "|" + _strKey;

IterStringMap iter = m_mapPairs.find(strMyKey);

if (iter != m_mapPairs.end())
{
std::string temp = ((*iter).second);
_iValue = atoi(temp.c_str());

return true;
}

return false;
}

I hope that helps. If I can convert a char to a strgin somehow, I'll be happy. And if I can get a std::string piece of code that will single out a character within a string, I'll be equally happy. Again, thanks for your help, guys. :)

Share this post


Link to post
Share on other sites
TDragon    679
1. std::string is equivalent to std::basic_string< char >, as has been pointed out. All operations on and members of the latter work with the former. Many people will get confused if you use the latter, so use the former.

2. If you really want to pass only a single character as the first argument to GetIntValue, pass it by value, not by reference. If you're actually wanting to pass a substring of the original string, use the substr() function.

3. The original code you posted has no effect. Each time through the loop, it searches four times for a key named "frame" in a block named whatever the character at i is, and writes the value if found to a temporary variable inside the loop. Is this your actual code?

EDIT:
Quote:
If I can convert a char to a strgin somehow, I'll be happy. And if I can get a std::string piece of code that will single out a character within a string, I'll be equally happy.
For the first, std::string has a constructor that takes a number and a char; it also has an assignment (=) operator that takes a char. For the second, the index operator.

std::string mystring = "Hello, world!";
char c = mystring[4]; // 'o'

Share this post


Link to post
Share on other sites
Jesbass    122
Quote:
Original post by TDragon
1. std::string is equivalent to std::basic_string< char >, as has been pointed out. All operations on and members of the latter work with the former. Many people will get confused if you use the latter, so use the former.


So how do I use std::string to retrieve a single character, if that is the case?

Quote:
Original post by TDragon
2. If you really want to pass only a single character as the first argument to GetIntValue, pass it by value, not by reference. If you're actually wanting to pass a substring of the original string, use the substr() function.


Yeah, only a single character. How do I pass it by value instead of by reference?

Quote:
Original post by TDragon
3. The original code you posted has no effect. Each time through the loop, it searches four times for a key named "frame" in a block named whatever the character at i is, and writes the value if found to a temporary variable inside the loop. Is this your actual code?


Yes, that's my actual code. That's all I want it do for now. Once I've removed my errors I can move onto the next piece of code related to this code segment. I am of the understanding that it would be bad programming practice to simply continue on by ignoring the errors I'm receiving.

Share this post


Link to post
Share on other sites
TDragon    679
I answered your questions in an edit to my previous post just now. Sorry for any confusion/trouble. What I meant about passing by value was something along the lines of:

std::string str = _strStringName[i];
parser.GetIntValuestr(str, "frame", iStopY);

Share this post


Link to post
Share on other sites
Jesbass    122
Quote:
Original post by TDragon
I answered your questions in an edit to my previous post just now. Sorry for any confusion/trouble. What I meant about passing by value was something along the lines of:

std::string str = _strStringName[i];
parser.GetIntValuestr(str, "frame", iStopY);


Oh, I see what you mean. Yeah, that makes more sense, but my problem remains.

Share this post


Link to post
Share on other sites
TDragon    679
Which problem? Surely you're not still getting the original error message about being unable to convert from 'std::allocator<_Ty>::value_type' to 'std::string'?

Share this post


Link to post
Share on other sites
Jesbass    122
Quote:

bool CMyFont::Initialize(const Int8* _pcIniFileName, std::string _strStringName,
Float32 _fXPosition, Float32 _fYPosition)
{
CINIParser parser(_pcIniFileName);
Int32 iStringLength = static_cast<Int32>(_strStringName.length());

for(int i = 0; i < iStringLength; i++)
{
//std::string strCurrentLetter = _strStringName[i];
//std::basic_string <char>::reference strCurrentLetter = _strStringName[i];
Int32 iStartX;
Int32 iStopX;
Int32 iStartY;
Int32 iStopY;
parser.GetIntValue(_strStringName[i], "frame", iStartX);
parser.GetIntValue(_strStringName[i], "frame", iStopX);
parser.GetIntValue(_strStringName[i], "frame", iStartY);
parser.GetIntValue(_strStringName[i], "frame", iStopY);
}

return true;
}


Yes, unfortunately. The errors are slightly different, but I think the problem is the same. Here are the errors:

Quote:

e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(73): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string'
with
[
_Ty=char
]
e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(74): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string'
with
[
_Ty=char
]
No constructor could take the source type, or constructor overload resolution was ambiguous
e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(75): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string'
with
[
_Ty=char
]
No constructor could take the source type, or constructor overload resolution was ambiguous
e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(76): error C2664: 'CINIParser::GetIntValue' : cannot convert parameter 1 from 'std::allocator<_Ty>::value_type' to 'std::string'
with
[
_Ty=char
]
No constructor could take the source type, or constructor overload resolution was ambiguous

Share this post


Link to post
Share on other sites
TDragon    679
Quote:
Original post by TDragon
I answered your questions in an edit to my previous post just now. Sorry for any confusion/trouble. What I meant about passing by value was something along the lines of:

std::string str = _strStringName[i];
parser.GetIntValuestr(str, "frame", iStopY);


Read my lips...[smile]

Share this post


Link to post
Share on other sites
Jesbass    122
Ah. My bad. :P

I've done that, but now my error rest with this line of code:

Quote:

std::string strCurrentLetter = _strStringName[i];


And the error is this:

Quote:

e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(67): error C2440: 'initializing' : cannot convert from 'std::allocator<_Ty>::value_type' to 'std::basic_string<_Elem,_Traits,_Ax>'
with
[
_Ty=char
]
and
[
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]


Is there perhaps an include file that I should be using in order for this to work properly?

Share this post


Link to post
Share on other sites
TDragon    679
All you should need to include is <string>; I wish I had a compiler with me to test it. You could try casting it to a char: std::string strCurrentLetter = static_cast< char >(_strStringName[i]);

Share this post


Link to post
Share on other sites
Jesbass    122
Yeah, I've already included <string>.

static_casting it to a char results in this:

Quote:

e:\Documents and Settings\David & Angela\Desktop\Rugby League Manager\Font.cpp(67): error C2440: 'initializing' : cannot convert from 'char' to 'std::basic_string<_Elem,_Traits,_Ax>'
with
[
_Elem=char,
_Traits=std::char_traits<char>,
_Ax=std::allocator<char>
]


Ah well. I'm not sure where to go from here. Thanks for your help, though, TDragon. :)

Share this post


Link to post
Share on other sites
Jesbass    122
Wow, that did the trick! Thanks Phillip and TDragon! :)

Both of these work:

Quote:

std::string strCurrentLetter;
strCurrentLetter.assign(1, _strStringName[i]);


Quote:

std::string strCurrentLetter(1, _strStringName[i]);

Share this post


Link to post
Share on other sites
Phillip Martin    226
Actually I just realised why it wasn't working.

You were essentially doing:

std::string mystring = 'a';

Since mystring is being declared, it actually uses a constructor to initialise mystring, not the equals operator. And lo and behold, std::string doesn't have a constructor that takes a single argument of type char.

Mystery solved!

Share this post


Link to post
Share on other sites
Zahlman    1682

CINIParser::GetIntValue(std::string _strBlock, std::string _strKey, Int32& _iValue)
{
std::string strMyKey;

strMyKey = _strBlock + "|" + _strKey;

IterStringMap iter = m_mapPairs.find(strMyKey);

if (iter != m_mapPairs.end())
{
std::string temp = ((*iter).second);
_iValue = atoi(temp.c_str());

return true;
}

return false;
}


I assume the reason for passing a std::string is that some of the blocks will have labels more than one character long (so for our single-character labels, we just create new strings out of them and we're good to go). Returning the value by reference and having a boolean result code is only a good idea if 'not found' results are supposed to be common and/or expected; one might instead prefer to throw an exception and return the actual value. (But using the boolean return type instead of an int return or BOOL typedef is indeed a good idea.)

That said, I'd rewrite as follows:


bool CINIParser::GetIntValue(std::string _strBlock, std::string _strKey, Int32& _iValue) {
IterStringMap iter = m_mapPairs.find(_strBlock + "|" + _strKey);
if (iter == m_mapPairs.end()) return false;
// ugh, let's not use atoi() for parsing. Instead we'll read out the value
// with a stringstream. This will also allow us to detect the condition that
// the stored value isn't numeric. Also, (*iter).second is equivalent to
// iter->second, so:
std::stringstream parser(iter->second);
char garbage; // used to detect if there was anything extra in the data.
return (parser >> _iValue && !parser >> garbage);
// This may leave an unwanted value in _iValue if there was garbage, or
// fail to initialize _iValue, but _iValue is an out parameter so we don't
// really care - the caller should be checking the return value anyway.
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this