boost::program_options overloaded validate is ambiguous - boost

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

Related

Find a unique_ptr to an inherited class object emplaced_back in a vector

I am trying to implement an Entity Component System (ECS) for my game. I have a base class "Component" (referred here as A) which is inherited by child class like HealthComponent(referred here as B), DamageComponent (referred here C)
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
class A
{
public:
A() : VarA(10){}
int VarA;
const std::string ClassName = "A";
virtual void prnt(){ std::cout << "A class" << std::endl; }
};
class B : public A
{
public:
B() : VarB(20){}
int VarB;
const std::string ClassName = "B";
void prnt(){ std::cout << "B class" << std::endl; }
bool operator== (const B& other) const
{
return this->ClassName == other.ClassName;
}
};
class C : public A
{
public:
C() : VarC(30){}
int VarC;
const std::string ClassName = "C";
void prnt(){ std::cout << "C class" << std::endl; }
bool operator== (const B& other) const
{
return this->ClassName == other.ClassName;
}
};
int main()
{
std::vector<std::unique_ptr<A>> ObjVector;
std::vector<std::unique_ptr<A>>::iterator ObjIterator;
A* object1 = new B();
std::unique_ptr<A> bptr{object1};
ObjVector.emplace_back(std::move(bptr));
A* object2 = new C();
std::unique_ptr<A> cptr{object2};
ObjVector.emplace_back(std::move(cptr));
ObjIterator = std::find(ObjVector.begin(), ObjVector.end(), B);
return 0;
}
on compiling the code
-------------- Build: Debug in STL (compiler: GNU GCC Compiler)---------------
x86_64-w64-mingw32-g++.exe -Wall -g -std=c++11 -c C:\Users\admin\Desktop\code\C++\STL\main.cpp -o obj\Debug\main.o
x86_64-w64-mingw32-g++.exe -o bin\Debug\STL.exe obj\Debug\main.o
C:\Users\admin\Desktop\code\C++\STL\main.cpp: In function 'int main()':
C:\Users\admin\Desktop\code\C++\STL\main.cpp:58:66: error: expected primary-expression before ')' token
58 | ObjIterator = std::find(ObjVector.begin(), ObjVector.end(), B);
| ^
I tried using "new B()" and "(&B)" as the last parameter in std::find function but it still gave me errors. Please Help.
UPDATED CODE
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
class A
{
public:
A() : VarA(10){}
int VarA;
const std::string ClassName = "A";
virtual std::string getClassName(){ return ClassName; }
};
class B : public A
{
public:
B() : VarB(20){}
int VarB;
const std::string ClassName = "B";
std::string getClassName() override { return ClassName; }
};
class C : public A
{
public:
C() : VarC(30){}
int VarC;
const std::string ClassName = "C";
std::string getClassName() override { return ClassName; }
};
int main()
{
std::vector<std::unique_ptr<A>> ObjVector;
std::vector<std::unique_ptr<A>>::iterator ObjIterator;
A* object1 = new B();
std::unique_ptr<A> bptr{object1};
ObjVector.emplace_back(std::move(bptr));
A* object2 = new C();
std::unique_ptr<A> cptr{object2};
ObjVector.emplace_back(std::move(cptr));
ObjIterator = std::find_if(ObjVector.begin(), ObjVector.end(),
[](const std::unique_ptr<A>& p)
{
return dynamic_cast<B*>(p.get()) != nullptr;
});
std::cout << (*ObjIterator)->VarB << std::endl;
return 0;
}
Your solution worked and i changed some of the code accordingly. It gives me access to methods common to all class, here "getClassName()". But on accessing class specific methods and variables (here VarB, which is specific to class B) it gives me the following error
-------------- Build: Debug in STL (compiler: GNU GCC Compiler)---------------
x86_64-w64-mingw32-g++.exe -Wall -g -std=c++11 -c C:\Users\admin\Desktop\code\C++\STL\main.cpp -o obj\Debug\main.o
x86_64-w64-mingw32-g++.exe -o bin\Debug\STL.exe obj\Debug\main.o
C:\Users\admin\Desktop\code\C++\STL\main.cpp: In function 'int main()':
C:\Users\admin\Desktop\code\C++\STL\main.cpp:55:34: error: 'class A' has no member named 'VarB'; did you mean 'VarA'?
55 | std::cout << (*ObjIterator)->VarB << std::endl;
| ^~~~
| VarA
Basically I cannot access the methods and variables that are not included in the base class. What am I doing wrong here?

Error including boost/spirit/include/qi.hpp

I'm having the same error as occurs here. See 'compilation info' at the bottom for the long error message. Basically if I #include <boost/spirit/include/qi.hpp> I can't compile. Totally stumped by this one... I am compiling with g++ 4.9.3 on Debian using C++11. For reference the first part of the error message is:
In file included from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:35:0,
from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
from /usr/include/boost/spirit/home/qi.hpp:20,
from /usr/include/boost/spirit/include/qi.hpp:16,
from prog.cpp:9:
/usr/include/boost/spirit/home/qi/reference.hpp: In instantiation of 'bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<std::basic_string<char>&, boost::fusion::nil_>, boost::spirit::locals<> >; Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >; Attribute = std::basic_string<char>; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::basic_string<char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>]':
My code is actually a little bit different to the above example:
My::Dictionary Parser::parse( const char * s ) {
std::string input(s); // input to parse
qi_my_protocol grammar; // create instance of parser
My::Dictionary msg; // map to receive results
bool result = qi::phrase_parse(
input.begin(),
input.end(),
grammar,
qi::space,
msg
); // returns true if successful
return msg;
}
Your string isn't const, so the iterators first and last aren't const iterators.
Either make the my_Parse function not a template (after all, you hardcode the iterator type on the grammar to be std::string::const_iterator anyways), or instantiate the grammar with the actual iterator type:
my_grammar<Iterator> g;
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <stdio.h>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
template <typename Iterator>
struct my_grammar : boost::spirit::qi::grammar<Iterator, std::string(), ascii::space_type>
{
my_grammar() : my_grammar::base_type(start)
{
using qi::alpha;
using qi::alnum;
start %=
(+alpha | +alnum)
;
}
qi::rule<Iterator, std::string(), ascii::space_type> start;
};
template <typename Iterator>
bool my_Parse(Iterator first, Iterator last, std::string& result)
{
using boost::spirit::ascii::space;
my_grammar<Iterator> g;
bool r = phrase_parse(first, last, g, space, result);
if (!r || first != last) // fail if we did not get a full match
return false;
return r;
}
int main() {
std::string str;
while (getline(std::cin, str))
{
std::string result = "";
if (my_Parse(str.begin(), str.end(), result))
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "got: " << result << std::endl;
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
}
}

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>>.

Clang OS X compiler balks on this code but it works fine on Linux

The following sample code works fine under linux using g++4.8.2, using boost1_56. However, I get a strange linker error under MacOS X (Yosemite) using clang:
ld: internal error: atom not found in symbolIndex(__ZNSt3__112__hash_tableINS_17__hash_value_typeIKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEN15FRUIT_TUPLES4dataEEENS_22__unordered_map_hasherIS8_SB_NS9_8key_hashELb1EEENS_21__unordered_map_equalIS8_SB_NS9_9key_equalELb1EEENS5_ISB_EEE15__insert_uniqueIRKNS_4pairIS8_SA_EEEENSL_INS_15__hash_iteratorIPNS_11__hash_nodeISB_PvEEEEbEEOT_) for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Proces
The main.cpp file
#include "TupleFruits.hpp"
int main()
{
map_t fruitHash = InitializeFruitHash();
std::string fruit = "BANANA";
auto itr = fruitHash(fruit);
if (fruitHash.end() == itr)
{
std::cout << fruit << " not found in hash" << std::endl;
exit(1);
}
}
The FruitHash.cpp file:
#include "TupleFruits.hpp"
map_t InitializeFruitHash()
{
static map_t m;
data dBANANA = {0, 0, 6, false};
data dGRAPEFRUIT = {1, 1, 6, false};
data dSTRAWBERRY = {2, 2, 6, false};
m[BANANA] = dBANANA;
m[GRAPEFRUIT] = dGRAPEFRUIT;
m[STRAWBERRY] = dSTRAWBERRY;
return m;
}
The include file "HashData.hpp
#ifndef HASH_DATA_HPP
#define HASH_DATA_HPP
#include <string>
#include <unordered_map>
#include <cstring>
#include <iostream>
#include <tuple>
#include <boost/functional/hash.hpp>
typedef std::string fruit_key_t;
namespace HASH_TUPLES
{
struct key_hash : public std::unary_function<fruit_key_t, std::size_t>
{
std::size_t operator()(const fruit_key_t& k) const
{
std::hash<std::string> hash_fn;
return hash_fn(k);
}
};
struct key_equal : public std::binary_function<fruit_key_t, fruit_key_t, bool>
{
bool operator()(const fruit_key_t& v0, const fruit_key_t& v1) const
{
return (v0 == v1);
}
};
struct data
{
int row;
int column;
int precision;
bool isRipe;
inline bool operator ==(data d)
{
if (d.row == row && d.column == column)
return true;
else
return false;
}
friend std::ostream& operator << (std::ostream& os, const data& rhs) //Overloaded operator for '<<'
{ //for struct output
os << rhs.row << ", "
<< rhs.column;
return os;
}
};
typedef std::unordered_map<const fruit_key_t, data, key_hash, key_equal> map_t;
// ^ this is our custom hash
}
template<class T>
struct map_data_compare : public std::binary_function<typename T::value_type,
typename T::mapped_type,
bool>
{
public:
bool operator() (typename T::value_type &pair,
typename T::mapped_type i) const
{
return pair.second == i;
}
};
#endif
The include file "TupleFruits.hpp"
#ifndef TUPLESFRUITS_HPP
#define TUPLESFRUITS_HPP
#include <boost/interprocess/containers/string.hpp>
#include "HashData.hpp"
using namespace HASH_TUPLES;
map_t InitializeFruitHash();
static std::string BANANA = "banana";
static std::string GRAPEFRUIT = "grapefruit";
static std::string STRAWBERRY = "strawberry";
#endif
I figured it out. Somehow -s (strip all symbols from binary) snuck in my Makefile

Resources