How to pass a char to `boost::char_separator<char>` - boost

Based on How do I tokenize a string in C++?
explicit char_separator(const Char* dropped_delims,
const Char* kept_delims = "",
empty_token_policy empty_tokens = drop_empty_tokens)
#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
using namespace std;
using namespace boost;
int main(int, char**)
{
string text = "token, test string";
char_separator<char> sep(", ");
tokenizer< char_separator<char> > tokens(text, sep);
BOOST_FOREACH (const string& t, tokens) {
cout << t << "." << endl;
}
}
I need to pass in a char as the separator as follows:
void splitString(const string& text, char sepChar)
{
char_separator<char> sep(&sepChar);
tokenizer< char_separator<char> > tokens(text, sep);
BOOST_FOREACH (const string& t, tokens) {
cout << t << "." << endl;
}
}
Question> Is this right way to convert char to const char* for boost::char_separator?
Thank you

Related

How to have a tuple as both the key and value of an unordered map using a hash function or boost?

I am trying to use a tuple<string, string, string> that will be placed as both the key and value of the unordered map as such:
unordered_map < tuple<string, string, string>, tuple<string, string, string>, hash_tuple> songInfo;
I understand I'm supposed to define a hash function because C++ does not have a hasher for std::tuple. However, I'm struggling to implement this through the explanations I've been reading on the other stack overflow posts. This is what my code has so far:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <tuple>
using namespace std;
typedef std::tuple<string, string, string> t;
struct hash_tuple : public unary_function <t, size_t> {
size_t operator()(const t& x) const
{
return get<0>(x) ^ get<1>(x) ^ get<2>(x);
}
};
typedef unordered_map <t, t, hash_tuple> songInfo;
int main() {
string filePath = "../data/songInfo.txt";
fstream songFile;
songFile.open("songInfo.txt");
string line;
string name, artist, date, duration, genre, mood;
vector <string> store;
while (getline(songFile, line, ',')) {
store.push_back(line);
tuple <string, string, string> iD(store[0], store[1], store[2]);
tuple <string, string, string> info(store[3], store[4], store[5]);
songInfo[iD] = info;
}
for (auto it = songInfo.begin(); it != songInfo.end(); it++)
cout << "[" << get<0>(it->first) << ", " << get<1>(it->first) << ", " <<
get<2>(it->first) << "] ==>" << get<0>(it->second) << ", " << get<1>(it-
>second) << ", " << get<2>(it->second) << endl;
}
Okay "fixing" the problem is easy: you wanted to XOR-combine hashes, not strings:
struct hash_tuple {
size_t operator()(const t& x) const {
std::hash<std::string> h{};
return h(get<0>(x)) ^ h(get<1>(x)) ^ h(get<2>(x));
}
};
Note that using namespace std is frowned upon, using declarations trump typedefs and unary_function<> is deprecated. Next up there were some syntax errors.
Combining fixes for these: Live On Coliru
#include <fstream>
#include <iostream>
#include <tuple>
#include <unordered_map>
#include <vector>
using t = std::tuple<std::string, std::string, std::string>;
struct hash_tuple {
size_t operator()(const t& x) const {
std::hash<std::string> h{};
return h(get<0>(x)) ^ h(get<1>(x)) ^ h(get<2>(x));
}
};
using SongInfo = std::unordered_map<t, t, hash_tuple>;
int main() {
std::string filePath = "songInfo.txt";
std::fstream songFile;
songFile.open("songInfo.txt");
std::string line;
std::string name, artist, date, duration, genre, mood;
std::vector<std::string> store;
SongInfo songInfo;
while (getline(songFile, line, ',')) {
store.push_back(line);
std::tuple<std::string, std::string, std::string> iD(store[0], store[1], store[2]);
std::tuple<std::string, std::string, std::string> info(store[3], store[4], store[5]);
songInfo[iD] = info;
}
for (auto it = songInfo.begin(); it != songInfo.end(); it++)
std::cout << "[" << get<0>(it->first) << ", " << get<1>(it->first)
<< ", " << get<2>(it->first) << "] ==>" << get<0>(it->second)
<< ", " << get<1>(it->second) << ", " << get<2>(it->second)
<< std::endl;
}

Why do I need to set boost::archive::no_codecvt when using textarchive?

We have a class that serialises to boost::archive; but it inserts a 7 character string before the beginning of the archive.
Since upgrading to boost 1.61 from 1.56, this has started failing.
We've found that replacing the line:
boost::archive::polymorphic_text_iarchive ia(ifs);
with
boost::archive::polymorphic_text_iarchive ia(ifs, boost::archive::no_codecvt);
fixes the problem. But it would be nice to know why this has started failing between 1.56 and 1.61, and if this is the correct way to solve the issue.
// boost_archiving.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <boost/exception/exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
struct SimpleStruct
{
int x;
int y;
std::string string;
double dub;
template<typename T_ARCHIVE>
void serialize(T_ARCHIVE &a, unsigned int version)
{
a & x;
a & y;
a & string;
a & dub;
}
};
typedef boost::array<char, 7> FileId;
const FileId FILE_ID = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
void writeFile(const std::string& filename)
{
std::ofstream ofs(filename.c_str());
ofs.write(FILE_ID.data(), FILE_ID.size());
boost::archive::text_oarchive oa(ofs);
SimpleStruct simple;
simple.x = 10;
simple.y = 7;
simple.string = "test";
simple.dub = 2.5;
oa << simple;
}
void readFile(const std::string& filename)
{
std::ifstream ifs(filename.c_str());
FileId fileId;
ifs.read(fileId.data(), fileId.size());
if (ifs.good() && (fileId == FILE_ID))
{
boost::archive::polymorphic_text_iarchive ia(ifs); // FAILS on 1.61 Swap this with the line below, or downgrade to boost 1.56
// boost::archive::polymorphic_text_iarchive ia(ifs, boost::archive::no_codecvt);
SimpleStruct simple;
ia >> simple;
std::cout
<< simple.x << " "
<< simple.y << " "
<< simple.string << " "
<< simple.dub << std::endl;
}
}
void main(int argc, char* argv[])
{
try
{
std::string filename("archive.arch");
writeFile(filename);
readFile(filename);
}
catch (const std::exception& e)
{
std::cerr << boost::current_exception_diagnostic_information() << std::endl;
}
}
Sample Archive:
abcdefg22 serialization::archive 11 0 0 10 7 4 test 2.50000000000000000e+000

variadic template argument for std::function

Recently, I've been working on a little project alongside my c++ game-dev engine : it's a programming language, written in C++, in one header, named kickC. Here is what I have done so far : (See question below)
#ifndef KICK_C_INCLUDED_H
#define KICK_C_INCLUDED_H
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <exception>
#include <functional>
#include <unordered_map>
#include <vector>
#define LOG(x) std::cout << x << std::endl;
namespace strutil
{
inline unsigned CountWords(const std::string& value){
std::string temp = value;
std::replace_if(temp.begin(), temp.end(), std::ptr_fun<int, int>(std::isspace), ' ');
temp.erase(0, temp.find_first_not_of(" "));
if(temp.empty())
return 0;
return std::count(temp.begin(), std::unique(temp.begin(), temp.end()), ' ') + !std::isspace(*value.rbegin());
}
}
class KickCException : std::exception
{
public:
explicit KickCException(const char* msg, bool fatal = false)
: msg_(msg){}
explicit KickCException(const std::string& msg)
: msg_(msg){}
virtual ~KickCException() throw(){}
virtual const char* what() const throw(){
return std::string("[error :] [")
.append(msg_)
.append("]")
.c_str();
}
protected:
std::string msg_;
};
class KickCFileException : KickCException
{
public:
explicit KickCFileException(const char* msg)
: KickCException(msg){}
explicit KickCFileException(const std::string& msg)
: KickCException(msg){}
virtual ~KickCFileException() throw(){}
const char* what() const throw() override{
return std::string("[file error :] [")
.append(msg_)
.append("]")
.c_str();
}
};
class KickCEmptyStringException : KickCException
{
public:
explicit KickCEmptyStringException(const char* msg)
: KickCException(msg){}
explicit KickCEmptyStringException(const std::string& msg)
: KickCException(msg){}
virtual ~KickCEmptyStringException() throw(){}
const char* what() const throw() override{
return std::string("[empty string error :] [")
.append(msg_)
.append("]")
.c_str();
}
};
class KickCAPIBehaviourImplementation
{
public:
KickCAPIBehaviourImplementation(){}
~KickCAPIBehaviourImplementation(){}
void AddDefined(const std::string& str, std::function<void(void)> func){
m_values[str] = func;
}
void ParseAndApplyLine(const std::string& line){
std::istringstream iss(line);
for(unsigned i = 0; i < strutil::CountWords(line); ++i){
static std::string word = "";
iss >> word;
for(auto it_map = m_values.begin(); it_map != m_values.end(); ++it_map){
if(it_map->first == word)
{
(it_map->second)(/*HERE ! GIVE SOME ARGUMENTS ! */);
}
}
}
}
private:
std::unordered_map<std::string, std::function<void(void)>> ///so far, args is void... m_values;
};
#endif //KICK_C_INCLUDED_H
///src
int main(int argc, const char** args){
std::ifstream file("script.kick");
KickCAPIBehaviourImplementation kickCApiBehaviour;
try{
if(!file.is_open())
throw KickCFileException("unvalid fileName taken at input");
kickCApiBehaviour.AddDefined("print", [&](void){std::cout << "print found !" << std::endl;});
while(!file.eof()){
std::string line;
std::getline(file, line);
kickCApiBehaviour.ParseAndApplyLine(line);
}
}catch(KickCException& e){
LOG(e.what());
}
file.close();
std::cin.get();
}
So here is the Question : I would like to pass std::function (see class KickCAPIBehaviourImplementation ) a variable argument of types : I need to use variatic templates, of course, but the question how can I implement it so i end up calling my functions like this ?
kickCApiBehaviour.AddDefined("print", [&](int arg1, char * arg2, int arg3){std::cout << arg1 << arg2 << arg3 << std::endl;});
Move the parser into the std::function.
Where you add the function, include a signature:
// helper type:
template<class T>struct tag{using type=T;};
kickCApiBehaviour.AddDefined(
"print", // the name
tag<void(int,char*,int)>{}, // the signature
[&](int arg1, char * arg2, int arg3){
std::cout << arg1 << arg2 << arg3 << std::endl;
} // the operation
);
store a std::function< error_code(ParserState*) >. Inside AddDefined, store a lambda that includes a call to the code that parses arguments and calls the passed in lambda:
template<class R, class...Args, class F>
void AddDefined(std::string name, tag<R(Args...)>, F f) {
std::function< error_code(ParserState*) > r =
[f](ParserState* self)->error_code {
// here, parse each of Args... out of `self`
// then call `f`. Store its return value,
// back in `self`. If there is a parse error (argument mismatch, etc),
// return an error code, otherwise return no_error
};
m_values[name] = r;
};
then m_values contains the operation "take a parser state, and parse the arguments, and call the function in question on them".

(C++) error: use of overloaded operator '<<' is ambiguous (with operand types 'ostream' (aka 'basic_ostream<char>')

I overloaded the Extraction and Insertion operators. But now whenever they're being called in main.cpp the compiler tells me that there's an ambuiguity error. I sorta understand what ambiguity errors are, but I can't for the life of me figure out why it's happening.
I'm using g++ compiler and LLDB debugger if it helps.
The Error:
/Users/Final Project/ms1.cpp:147:12: error: use of overloaded operator '<<' is ambiguous (with operand types 'ostream' (aka 'basic_ostream<char>') and 'oop244::Date')
cout << A << " is not equal to " << B << " but operator!= returns otherwise!" << endl;
~~~~ ^ ~
/Users/Final Project/Date.h:57:17: note: candidate function
std::ostream& operator<<(std::ostream os, Date& Dob);
Followed by a billion other similar errors.
My main (where the error occurs):
#include <iostream>
#include <cstring>
#include "Date.h"
#include "Date.cpp"
#include "general.h"
using namespace std;
using namespace oop244;
bool equalDates(const char* A, const char* B);
int main(){
int ret = 0;
char confirm[2000];
bool ok = true;
Date A(2018, 10, 18);
Date B;
......
......
A = Date(2018, 10, 17);
if (ok){
cout << "testing operator!=" << endl;
if (A != B){
cout << "passed!" << endl;
}
else{
cout << A << " is not equal to " << B << " but operator!= returns otherwise!" << endl;
ok = false;
}
}
Class declaration
#ifndef __244_DATE_H__
#define __244_DATE_H__
// header file includes
#include "general.h"
#include <string>
#include <iostream>
namespace oop244{
class Date{
private:
// private member variables
int _year;
int _mon;
int _day;
int _readErrorCode;
// private member functions and setters
int value()const;
void setErrCode(int errCode);
.....
.....
public:
// constructors
Date();
Date(int,int,int);
~Date();
std::ostream& write(std::ostream& ostr, Date& dob);
std::istream& read(std::istream& istr, Date& dob);
};
std::istream& operator>>(std::istream is, Date& dob);
std::ostream& operator<<(std::ostream os, Date& dob);
}
#endif
Class function definitions
#include "general.h"
#include "Date.h"
#include <iomanip>
#include <iostream>
using namespace std;
namespace oop244{
// constructors
Date::Date()
{
_year=0;
_mon=0;
_day=0;
_readErrorCode=NO_ERROR;
}
Date::Date(int year,int month, int day)
{
_year=year;
_mon=month;
_day=day;
_readErrorCode=NO_ERROR;
}
Date::~Date() {}
// member functions
void Date::setErrCode(int errCode)
{
_readErrorCode=errCode;
}
void Date::passErr(int errCode)
{
setErrCode(errCode);
}
.....
.....
int Date::getErrCode() const
{
return _readErrorCode;
}
std::istream& Date::read(std::istream& istr, Date& dob)
{
char y[5],m[3],d[3];
int year,month,day;
istr.getline(y,5,'/');
istr.getline(m,3,'/');
istr.getline(d,3,'/');
year=atoi(y);
month=atoi(m);
day=atoi(d);
Date temp (year,month,day);
if (year>=2000 && year<=2030)
dob.passErr(YEAR_ERROR);
else if (month+=1 && month<=12)
dob.passErr(MON_ERROR);
else if (day>=1 && day<=31)
dob.passErr(DAY_ERROR);
else
{
dob.passErr(NO_ERROR);
dob=temp;
}
return istr;
}
std::ostream& Date::write(std::ostream& ostr, Date& dob)
{
int year=dob.getYear();
int month=dob.getMonth();
int day=dob.getDay();
ostr<<year<<"/"<<month<<"/"<<day<<endl;
return ostr;
}
// non-memeber operator overloads
std::istream& operator>>(std::istream& is, Date& dob)
{
dob.read(is,dob);
return is;
}
std::ostream& operator<<(std::ostream& os, Date& dob)
{
dob.write(os,dob);
return os;
}
}
Sorry for the super long post. I'm kinda at the end of my wits. My thank to you guys in advance.
Looks like the function prototypes for operator>> and operator<< don't match their parameters with the definitions. In other words:
std::ostream& operator<<(std::ostream os, Date& dob);
in your header file is missing the & for the std::ostream. Same for operator>>.

boost::program_options overloaded validate is ambiguous

I am trying to parse a list input from the command line.
My class is derived from vector
The compiler complains about a overloaded validate being ambiguous.
I can see why, but do not know how to solve this issue.
Please help.
Below is a minimal example that generates the error. If the type of ch_list is changed to a vector, this minimal example compiles.
// g++ -std=c++11 -Wall -Wextra -pedantic test.cpp -o test -lboost_program_options -lboost_system
#include <vector>
#include <boost/program_options.hpp>
#include <iostream>
#include <vector>
using namespace std;
class mylist : public vector<int> {
public:
friend istream &operator>>(istream &is, mylist& l) {
int val;
is >> val;
l.push_back(val);
return is;
}
friend ostream& operator<<(ostream& os, const mylist& l) {
return os << l[0];
}
};
int main (int argc, char* argv[])
{
//vector<int> ch_list; // This works
mylist ch_list; // This doesn't
namespace po = boost::program_options;
po::options_description desc("Allowed options");
desc.add_options()
("ch", po::value<decltype(ch_list)>(&ch_list), "Set channel numbers")
;
po::variables_map vm;
try {
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
}
catch (po::error& e) {
cerr << "ERROR: " << e.what() << "\n";
return EXIT_FAILURE;
}
if (!ch_list.empty())
cout << ch_list[0] << "\n";
return EXIT_SUCCESS;
}
I get these errors
/usr/include/boost/program_options/detail/value_semantic.hpp: In instantiation of ‘void boost::program_options::typed_value<T, charT>::xparse(boost::any&, const std::vector<std::basic_string<charT> >&) const [with T = mylist; charT = char]’:
test.cpp:47:5: required from here
/usr/include/boost/program_options/detail/value_semantic.hpp:169:13: error: call of overloaded ‘validate(boost::any&, const std::vector<std::basic_string<char> >&, mylist*, int)’ is ambiguous
/usr/include/boost/program_options/detail/value_semantic.hpp:169:13: note: candidates are:
/usr/include/boost/program_options/detail/value_semantic.hpp:81:10: note: void boost::program_options::validate(boost::any&, const std::vector<std::basic_string<charT> >&, T*, long int) [with T = mylist; charT = char]
/usr/include/boost/program_options/detail/value_semantic.hpp:129:10: note: void boost::program_options::validate(boost::any&, const std::vector<std::basic_string<charT> >&, std::vector<_RealType>*, int) [with T = int; charT = char]
You can use custom validator. Your code would be:
#include <vector>
#include <boost/program_options.hpp>
#include <iostream>
#include <vector>
using namespace std;
namespace po = boost::program_options;
class mylist : public vector<int> {
public:
};
void validate(boost::any& v,
const vector<string>& values,
mylist*, int) {
mylist dvalues;
for(vector<string>::const_iterator it = values.begin();
it != values.end();
++it) {
stringstream ss(*it);
copy(istream_iterator<int>(ss), istream_iterator<int>(),
back_inserter(dvalues));
if(!ss.eof()) {
throw ("Invalid coordinate specification");
}
}
v = mylist(dvalues);
}
int main (int argc, char* argv[])
{
//vector<int> ch_list; // This works
mylist ch_list; // This doesn't
po::options_description desc("Allowed options");
desc.add_options()
("ch", po::value< mylist >(&ch_list)->multitoken(), "Set channel numbers")
;
po::variables_map vm;
try {
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
}
catch (po::error& e) {
cerr << "ERROR: " << e.what() << "\n";
return EXIT_FAILURE;
}
for (auto cc : ch_list)
cout << cc << endl;
return EXIT_SUCCESS;
}
Reference: boost::program_options config file option with multiple tokens

Resources