I've seen some answers to other boost::lexical_cast questions that assert the following is possible:
bool b = boost::lexical_cast< bool >("true");
This doesn't work for me with g++ 4.4.3 boost 1.43. (Maybe it's true that it works on a platform where std::boolalpha is set by default)
This is a nice solution to the string to bool problem but it lacks input validation that boost::lexical_cast provides.
In addition to the answer form poindexter, you can wrap the method from here in a specialized version of boost::lexical_cast:
namespace boost {
template<>
bool lexical_cast<bool, std::string>(const std::string& arg) {
std::istringstream ss(arg);
bool b;
ss >> std::boolalpha >> b;
return b;
}
template<>
std::string lexical_cast<std::string, bool>(const bool& b) {
std::ostringstream ss;
ss << std::boolalpha << b;
return ss.str();
}
}
And use it:
#include <iostream>
#include <boost/lexical_cast.hpp>
//... specializations
int main() {
bool b = boost::lexical_cast<bool>(std::string("true"));
std::cout << std::boolalpha << b << std::endl;
std::string txt = boost::lexical_cast< std::string >(b);
std::cout << txt << std::endl;
return 0;
}
I personally liked this approach because it hides any special code (e.g. using LocaleBool or to_bool(...) from the link) for converting to/from bools.
I'm posting the answer to my own question here for others who may be looking for something like this:
struct LocaleBool {
bool data;
LocaleBool() {}
LocaleBool( bool data ) : data(data) {}
operator bool() const { return data; }
friend std::ostream & operator << ( std::ostream &out, LocaleBool b ) {
out << std::boolalpha << b.data;
return out;
}
friend std::istream & operator >> ( std::istream &in, LocaleBool &b ) {
in >> std::boolalpha >> b.data;
return in;
}
};
usage:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include "LocaleBool.hpp"
int main() {
bool b = boost::lexical_cast< LocaleBool >("true");
std::cout << std::boolalpha << b << std::endl;
std::string txt = boost::lexical_cast< std::string >( LocaleBool( b ) );
std::cout << txt << std::endl;
return 0;
}
Put together your own template on top of boost lexical cast for parsing. Note the "default" parameter in the example to ensure overloading works correctly (feel free to use another means if you want).
template<typename T>
T Parse(const std::string& valStr, const T& default=T()) {
T result = boost::lexical_cast<T>(valStr);
}
Then, you can specialize for ANYTHING, including bools:
template<>
bool Parse(const std::string& valStr, const bool& default=true) {
if(strcmp(valStr.c_str(), "true") == 0) {
return true;
}
return false;
}
Obviously there are a number of ways to do this, and you can add more conditions for true vs false (I'd make sure all variants of "TRUE" and "FALSE" like "True", plus "T" and "F" work right). You could even extend it to numeric parsing.
Related
I am trying to swap strings. For one of my functions of my class, I am passing in two strings and I also created a temp variable. I have been trying to compile my code, but it says "no suitable function for conversion from std::string to const char* exists.
void CdLib::swap(string *s1, string *s2)
{
string temp;
strcpy(temp, *s1);
strcpy(*s1, *s2);
strcpy(*s1, temp);
}
class CdLib
{
public:
int n;
char Cd[N_MAX];
string artist;
string title;
int year;
string genre;
string fan;
string imageURL;
CdLib();
void setFromFile(string fileName);
void print(string label);
void sortByYear();
void sortByArtist();
void sortByTitle(string genres[]);
private:
void swap(int *a, int *b);
void swapStrings(string *s1, string *s2);
};
I'm confused why it is trying to convert between string and char when they should all be string. Thank you.
strcpy() takes char* pointers, not string* pointers. It you are not allocating any memory for strcpy() to copy into.
Rather than using strcpy() at all, a better solution is to use std::string::operator= instead:
void CdLib::swap(string *s1, string *s2)
{
string temp = *s1;
*s1 = *s2;
*s1 = temp;
}
Or better, std::swap():
void CdLib::swap(string *s1, string *s2)
{
std::swap(*s1, *s2);
}
I am trying to swap strings
Why would you need to? Sorting can be accomplished via std::sort and you don't have to worry about how the strings get swapped - that's the beauty of C++, such basic operations are all implemented in the standard library.
std::swap supports pretty much everything, so use that.
Don't pass strings as arguments by value. Pass them by const reference. Return them by value. If a function is intended to modify a string in place, then it should take it by non-const reference (i.e. "just" a reference).
Don't write using namespace std - it's bad practice.
I guess that the CdLib class is some sort of a CD library, but you haven't told us what else your program should do.
If I were to write a sketch of this, I'd start with a structure representing the CD information, comparison functions for the CD that can be used in sorting, a function to print out the CD information, and a way to stream the CD information to/from an ostream/istream:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct CDInfo
{
std::string artist;
std::string title;
std::string genre;
std::string fan;
std::string imageUrl;
int year;
friend void swap(CDInfo& a, CDInfo& b)
{
// see https://stackoverflow.com/a/2684544/1329652 for rationale
using std::swap; // bring in swap for built-in types
swap(a.artist, b.artist);
swap(a.title, b.title);
swap(a.genre, b.genre);
swap(a.fan, b.fan);
swap(a.imageUrl, b.imageUrl);
swap(a.year, b.year);
}
};
bool lessByYear(const CDInfo &l, const CDInfo &r) {
return l.year < r.year;
}
bool lessByArtist(const CDInfo &l, const CDInfo &r) {
return l.artist < r.artist;
}
void print(std::ostream &os, const CDInfo &cd) {
os << "Artist: " << cd.artist
<< "\n Title: " << cd.title
<< "\n Genre: " << cd.genre
<< "\n Fan: " << cd.fan
<< "\n Image: " << cd.imageUrl
<< "\n Year: " << cd.year << "\n";
}
std::istream &operator>>(std::istream &is, CDInfo &cd)
{
std::string year;
std::getline(is, cd.artist);
std::getline(is, cd.title);
std::getline(is, cd.genre);
std::getline(is, cd.fan);
std::getline(is, cd.imageUrl);
if (std::getline(is, year)) cd.year = std::stoi(year);
return is;
}
std::ostream &operator<<(std::ostream &os, const CDInfo &cd)
{
os << cd.artist << '\n' << cd.title << '\n'
<< cd.genre << '\n' << cd.fan << '\n'
<< cd.imageUrl << '\n' << cd.year << '\n';
return os;
}
Then I'd write a class representing the CD library, with methods to access the individual CDs, iterators to access the entire collection, methods using the std::sort algorithm and the comparison functions to sort the library, and methods to load/save it from/to file, and to print the entire library (by default to stdout):
class CDLibrary
{
std::vector<CDInfo> m_CDs;
public:
CDLibrary() = default;
int count() const { return m_CDs.size(); }
void resize(int newCount) { m_CDs.resize(newCount); }
CDInfo &getCD(int index) { return m_CDs[index]; }
const CDInfo &getCD(int index) const { return m_CDs[index]; }
auto begin() { return m_CDs.begin(); }
auto end() { return m_CDs.end(); }
auto begin() const { return m_CDs.begin(); }
auto end() const { return m_CDs.end(); }
auto cbegin() const { return m_CDs.begin(); }
auto cend() const { return m_CDs.end(); }
void sortByYear() {
std::sort(begin(), end(), lessByYear);
}
void sortByArtist() {
std::sort(begin(), end(), lessByArtist);
}
void addCD(const CDInfo &cd) {
m_CDs.push_back(cd);
}
void removeCD(int index) {
m_CDs.erase(m_CDs.begin() + index);
}
bool load(const std::string &filename);
bool save(const std::string &filename) const;
void printAll(std::ostream &os = std::cout) const {
int n = 1;
for (auto &cd : *this) {
os << "--- CD #" << n << '\n';
print(os, cd);
}
}
};
Of course I'd also implement the streaming operators for the entire library, just as we did for the individual CDInfo:
std::istream &operator>>(std::istream &is, CDLibrary &lib) {
std::string count;
if (std::getline(is, count)) {
lib.resize(std::stoi(count));
for (auto &cd : lib)
if (!(is >> cd)) break;
}
return is;
}
std::ostream &operator<<(std::ostream &os, const CDLibrary &lib) {
if (!(os << lib.count() << '\n')) return os;
for (auto &cd : lib)
if (!(os << cd)) break;
return os;
}
Then, the load and save convenience methods can be expressed n terms of those streaming operators:
bool CDLibrary::load(const std::string &filename) {
std::ifstream ifs(filename);
try {
return ifs.good() && ifs >> *this;
} catch (...) {}
return false;
}
bool CDLibrary::save(const std::string &filename) const {
std::ofstream ofs(filename);
return ofs.good() && ofs << *this;
}
Hopefully this gives you some idea how such code might look. I'm not quite sure what you expected to achieve with void sortByTitle(string genres[]), so I didn't implement it. Feel free to comment under this answer to explain, as well as edit the question to make it clear what is the functionality you need.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
string str1 = "Hello";
string str2 = "World";
swap(str1,str2);
cout<<str1<<" ";
cout<<str2;
}
o/p:
Success #stdin #stdout 0s 4492KB
World Hello
I want to implement a function like this
double d = string_to("1223.23",double);
int i = string_to("1223",int);
bool d = string_to("1",bool);
How can I pass the bool, int, double data type to implement this in c++?
Types line int, double and bool can only be passed as template parameters.
You can use templates like this:
#include <string>
#include <sstream>
#include <iostream>
template<typename DataType>
DataType string_to(const std::string& s)
{
DataType d;
std::istringstream(s) >> d; // convert string to DataType
return d;
}
int main()
{
double d = string_to<double>("1223.23");
int i = string_to<int>("1223");
bool b = string_to<bool>("1");
std::cout << "d: " << d << '\n';
std::cout << "i: " << i << '\n';
std::cout << "b: " << b << '\n';
}
As an alternative you can pass your numeric types by reference and rely on function overloading to select the correct function:
void string_to(const std::string& s, double& d)
{
d = std::stod(s);
}
void string_to(const std::string& s, int& i)
{
i = std::stoi(s);
}
void string_to(const std::string& s, bool& b)
{
std::istringstream(s) >> std::boolalpha >> b;
}
int main()
{
double d;
int i;
bool b;
string_to("1223.23", d);
string_to("1223", i);
string_to("true", b);
std::cout << "d: " << d << '\n';
std::cout << "i: " << i << '\n';
std::cout << "b: " << b << '\n';
}
Also you could templatize the second method (an exercise for the reader).
If you really want to do this, you can pass the type by using the typeid operator.
E.g. double d = string_to("1223.23", typeid(double));
Using the library functions atoi, stod would make more sense.
If you're aiming to write more uniform code then you could write a Converter object and use method overloading to get automatic selection by type.
class Converter
{
public:
void fromString(double& value, const char* string);
void fromString(int& value, const char* string);
void fromString(long& value, const char* string);
};
Here's another way that uses tag dispatching. You can compile and run this example.
#include <iostream>
#include <string>
#include <cmath>
namespace detail {
// declare the concept of conversion from a string to something
template<class To>
To string_to(const std::string&);
// make some models of the concept
template<>
int string_to<int>(const std::string& s) {
return atoi(s.c_str());
}
template<>
double string_to<double>(const std::string& s) {
return atof(s.c_str());
}
template<>
std::string string_to<std::string>(const std::string& s) {
return s;
}
// ... add more models here
}
// define the general case of conversion from string with a model tag
// note the unused parameter allows provision of a model that is never used
// thus the model will in all likelihood be optimised away
template<class To>
To string_to(const std::string& from, const To& /* model_tag is unused */)
{
// dispatch to correct conversion function using the To type
// as a dispatch tag type
return detail::string_to<To>(from);
}
using namespace std;
int main()
{
// examples
int a = string_to("100", a);
double b = string_to("99.9", b);
const string s = string_to("Hello", s);
cout << s << " " << a << " " << b << endl;
return 0;
}
output:
Hello 100 99.9
I have this class:
template<typename T> class Parser
{
public:
Parser() : count(0) {}
virtual void parse(const string&);
void get_token(void);
private:
T result;
char token;
string expression;
int count;
};
now had the class not been generic, had the result been say, a double, I would have used this method to detect numbers.
while((strchr("1234567890.",token))
{
/* add token to a "temp" string */
/* etc. etc. */
}
result = atof(temp.c_str());
But since result is generic, I can't use any method like atof and atoi etc.
What do I do?
Boost has this functionality built-in:
#include <boost/lexical_cast.hpp>
void Parser<T>::get_token() {
std::string token = ...;
result = boost::lexical_cast<T>(token);
}
Add exception handling as required.
Or, perhaps you don't want to use Boost for some reason:
void Parser<T>::get_token() {
std::string token = ...;
std::stringstream ss;
ss << token;
ss >> result;
}
Check the error state of ss as required.
More expansive answers may be found on this related question, though it discusses only int specifically.
Another generic template based Numeric To String converter. It takes ints and doubles.
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
template <class T>
inline std::string Numeric_To_String (const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
int main(int argc, char *argv[])
{
int i = 9;
double d = 1.2345;
string s;
cout <<"Generic Numeric_To_String( anyDatatype ) \n\n";
s = Numeric_To_String( i );
cout <<"int i to string : "<< s <<" "<< endl;
s = Numeric_To_String( d );
cout <<"double d to string : "<< s <<" "<< endl;
cout <<" \n";
return 0;
}
If you only have a hand full of types you want to parse, you can use template specialization:
template<>
void Parser<int>::parse(const string&)
{
result = atoi(string.c_str());
}
template<>
void Parser<float>::parse(const string&)
{
result = atof(string.c_str());
}
...
But this only works if you implement every convertion you need, of course.
With C++17 you can use the templated std::from_chars.
https://en.cppreference.com/w/cpp/utility/from_chars
#include <charconv>
#include <iostream>
template <typename Number>
auto stringTo(std::string_view str)
{
Number number;
std::from_chars(str.data(), str.data() + str.size(), number);
return number;
}
int main()
{
const auto str = std::string("42");
std::cout << stringTo<long>(str) << '\n';
std::cout << stringTo<double>(str) << '\n';
}
Check the return value of std::from_chars to detect errors.
const auto result = std::from_chars(...);
if (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)
{
std::cout << "string to number error" << '\n';
}
More info and examples: https://www.bfilipek.com/2018/12/fromchars.html
GCC and clang don't yet support the floating point version of std::from_chars (August 2019).
I was trying to think of a clever way to concatenate various things into a single string argument for a function without having to use an ostringstream explicitly. I thought of:
#define OSS(...) \
dynamic_cast<std::ostringstream const&>(std::ostringstream() << __VA_ARGS__).str()
However, given:
void f( string const &s ) {
cout << s << endl;
}
int main() {
char const *const s = "hello";
f( OSS( '{' << s << '}' ) );
ostringstream oss;
oss << '{' << s << '}';
cout << oss.str() << endl;
}
it prints when run:
123hello}
{hello}
where 123 is the ASCII code for }. Why does using the macro get it wrong?
FYI: I'm currently using g++ 4.2.1 on Mac OS X as part of Xcode 3.x.
Solution I'm now using
class string_builder {
public:
template<typename T>
string_builder& operator,( T const &t ) {
oss_ << t;
return *this;
}
operator std::string() const {
return oss_.str();
}
private:
std::ostringstream oss_;
};
#define BUILD_STRING(...) (string_builder(), __VA_ARGS__)
using namespace std;
void f( string const &s ) {
cout << s << endl;
}
int main() {
char const *const s = "hello";
f( BUILD_STRING( '{', s, '}' ) );
}
std::ostringstream() is temporary which thus can be bound only to const references. Standalone operator<< (which take non const references as first argument) aren't considered and only the member one are. The best match in these for a char is converting the char to int.
This problems occurs often with string literals whose address is then displayed.
To solve the problem, the trick is to find a way to transform the temporary in a reference. The member operator<<s do that, but only the one for manipulator does it without side effect and only if the manipulator is a noop -- flush could be used. The members flush and write are also candidates. So for instance
#define OSS(...) \
dynamic_cast<std::ostringstream const&>(std::ostringstream().flush() << __VA_ARGS__).str()
A better thread-safe solution without involving the cumbersome macro.
The original call to function is this:
f( OSS( '{' << s << '}' ) );
How about if the call is just this:
f(stringbuilder() << '{' << s << '}' );
where stringbuilder is implemented as:
struct stringbuilder
{
std::ostringstream ss;
template<typename T>
stringbuilder & operator << (const T &data)
{
ss << data;
return *this;
}
operator string() { return ss.str(); }
};
void f( string const &s ) {
cout << s << endl;
}
Test:
int main() {
char const *const s = "hello";
f(stringbuilder() << '{' << s << '}' );
}
Output:
{hello}
Online Demo : http://ideone.com/QHFf4
I've seen some answers to other boost::lexical_cast questions that assert the following is possible:
bool b = boost::lexical_cast< bool >("true");
This doesn't work for me with g++ 4.4.3 boost 1.43. (Maybe it's true that it works on a platform where std::boolalpha is set by default)
This is a nice solution to the string to bool problem but it lacks input validation that boost::lexical_cast provides.
In addition to the answer form poindexter, you can wrap the method from here in a specialized version of boost::lexical_cast:
namespace boost {
template<>
bool lexical_cast<bool, std::string>(const std::string& arg) {
std::istringstream ss(arg);
bool b;
ss >> std::boolalpha >> b;
return b;
}
template<>
std::string lexical_cast<std::string, bool>(const bool& b) {
std::ostringstream ss;
ss << std::boolalpha << b;
return ss.str();
}
}
And use it:
#include <iostream>
#include <boost/lexical_cast.hpp>
//... specializations
int main() {
bool b = boost::lexical_cast<bool>(std::string("true"));
std::cout << std::boolalpha << b << std::endl;
std::string txt = boost::lexical_cast< std::string >(b);
std::cout << txt << std::endl;
return 0;
}
I personally liked this approach because it hides any special code (e.g. using LocaleBool or to_bool(...) from the link) for converting to/from bools.
I'm posting the answer to my own question here for others who may be looking for something like this:
struct LocaleBool {
bool data;
LocaleBool() {}
LocaleBool( bool data ) : data(data) {}
operator bool() const { return data; }
friend std::ostream & operator << ( std::ostream &out, LocaleBool b ) {
out << std::boolalpha << b.data;
return out;
}
friend std::istream & operator >> ( std::istream &in, LocaleBool &b ) {
in >> std::boolalpha >> b.data;
return in;
}
};
usage:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include "LocaleBool.hpp"
int main() {
bool b = boost::lexical_cast< LocaleBool >("true");
std::cout << std::boolalpha << b << std::endl;
std::string txt = boost::lexical_cast< std::string >( LocaleBool( b ) );
std::cout << txt << std::endl;
return 0;
}
Put together your own template on top of boost lexical cast for parsing. Note the "default" parameter in the example to ensure overloading works correctly (feel free to use another means if you want).
template<typename T>
T Parse(const std::string& valStr, const T& default=T()) {
T result = boost::lexical_cast<T>(valStr);
}
Then, you can specialize for ANYTHING, including bools:
template<>
bool Parse(const std::string& valStr, const bool& default=true) {
if(strcmp(valStr.c_str(), "true") == 0) {
return true;
}
return false;
}
Obviously there are a number of ways to do this, and you can add more conditions for true vs false (I'd make sure all variants of "TRUE" and "FALSE" like "True", plus "T" and "F" work right). You could even extend it to numeric parsing.