I'm trying to write a class, that stores configuration items with their name, a description and their types.
OptionItem.h:
#include <typeinfo>
#include <string>
class OptionItem {
public:
OptionItem(std::string name, std::string text, type_info type);
std::string name() const;
std::string text() const;
type_info OptionItem::type() const;
private:
std::string _name, _text;
type_info _type;
};
OptionItem.cpp:
OptionItem::OptionItem(std::string name, std::string text, type_info type) :
_name(name), _text(text), _type(type) {};
std::string OptionItem::name() const { return _name; }
std::string OptionItem::text() const { return _text; }
type_info OptionItem::type() const { return _type; }
I have a second class that holds the different options:
Opt.h:
#include "OptionItem.h"
struct Opt {
static const OptionItem opt1, opt2;
};
Opt.cpp:
#include "myOwnClass.h"
const OptionItem Opt::opt1= OptionItem("Option 1", "text1", typeid(std::string));
const OptionItem Opt::opt2= OptionItem("Option 2", "text2", typeid(myOwnClass));
A third class that held the actual settings of my program would then look like this:
Settings.h
#include "OptionItem"
#include <any>
#include <map>
#include <string>
class Settings {
public:
void setOption(OptionItem option, std::any value);
template<class T> T& getOption(const std::string &option) const;
private:
std::map<std::string, std::any> _options;
}
Settings.cpp
void Settings::setOption(OptionItem option, std::any value) {
_options.emplace(option.name(), value);
}
T& Settings::getOption(const std::string &option) const {
if (_options.find(option) == _options.end()) {
throw(std::runtime_error("No such option \"" + option + "\"
}
else {
return std::any_cast<T>(_options[option]);
}
}
A call to Settings::getOption might look like this:
getOption<Opt::opt1.type()>(Opt::opt1.name())
I know this has its problems (which is, why I'm asking :-) ) the first one being that std::type_info doesn't seem to be copyable. (the compiler(VIsualCPP) tells me 'type_info::type_info(const type_info &)': attempting to reference a deleted function). The other problem, of which I am sure there are plenty I don't know about since compilation stops with the aforementioned error.
Do you have any suggestions how I could make this work?
Related
I'm having some problems with my code. A shared library is causing an undefined symbol error that I just cannot figure out. All of the files are in the correct locations and the shared library builds successfully but upon executing the program it returns the bellow message.
The error message:
libsp.so: undefined symbol: _ZTIN4Poco20NullPointerExceptionE
From what I can see the problem is the Poco headers I use. The headers I got from an outside source and they should all work, I believe the error is caused by how I call these headers, but I might be wrong.
Bellow is the only code that uses Poco in the libsp library. And the code of the 4 header files I use. I've checked and rechecked and cannot find any issues but am still getting the undefined symbol exception.
File Spexec.cpp (libsp):
#include "../poco/Poco/Base64Encoder.h"
#include "../poco/Poco/DigestEngine.h"
#include "../poco/Poco/MD5Engine.h"
#include "../poco/Poco/Path.h"
using namespace std;
stringstream s_base;
Poco::Base64Encoder encoder(s_base);
Poco::Path path(data.name);
data.path = data.name.substr(0, data.name.length() - path.getFileName().length());
Poco::MD5Engine md5;
stringstream ss;
ss << data.created << data.name;
md5.update(ss.str());
data.name = Poco::DigestEngine::digestToHex(md5.digest());
}
File Base64Encoder.h:
#ifndef Foundation_Base64Encoder_INCLUDED
#define Foundation_Base64Encoder_INCLUDED
#include "Foundation.h"
#include <ostream>
namespace Poco {
class Foundation_API Base64Encoder:, public std::ostream
{
public:
Base64Encoder(std::ostream& ostr);
~Base64Encoder();
private:
Base64Encoder(const Base64Encoder&);
Base64Encoder& operator = (const Base64Encoder&);
};
} // namespace Poco
#endif // Foundation_Base64Encoder_INCLUDED
File DigestEngine.h:
#ifndef Foundation_DigestEngine_INCLUDED
#define Foundation_DigestEngine_INCLUDED
#include "Foundation.h"
#include <vector>
namespace Poco {
class Foundation_API DigestEngine
{
public:
typedef std::vector<unsigned char> Digest;
DigestEngine();
virtual ~DigestEngine();
void update(const void* data, std::size_t length);
void update(char data);
void update(const std::string& data);
virtual std::size_t digestLength() const = 0;
virtual void reset() = 0;
virtual const Digest& digest() = 0;
static std::string digestToHex(const Digest& bytes);
static Digest digestFromHex(const std::string& digest);
presentation
protected:
virtual void updateImpl(const void* data, std::size_t length) = 0;
private:
DigestEngine(const DigestEngine&);
DigestEngine& operator = (const DigestEngine&);
};
File MD5Engine.h:
#ifndef Foundation_MD5Engine_INCLUDED
#define Foundation_MD5Engine_INCLUDED
#include "Foundation.h"
#include "DigestEngine.h"
namespace Poco {
class Foundation_API MD5Engine: public DigestEngine
{
public:
enum
{
BLOCK_SIZE = 64,
DIGEST_SIZE = 16
};
MD5Engine();
~MD5Engine();
std::size_t digestLength() const;
void reset();
const DigestEngine::Digest& digest();
protected:
void updateImpl(const void* data, std::size_t length);
private:
static void transform(UInt32 state[4], const unsigned char block[64]);
static void encode(unsigned char* output, const UInt32* input, std::size_t len);
static void decode(UInt32* output, const unsigned char* input, std::size_t len);
struct Context
{
UInt32 state[4]; // state (ABCD)
UInt32 count[2]; // number of bits, modulo 2^64 (lsb first)
unsigned char buffer[64]; // input buffer
};
Context _context;
DigestEngine::Digest _digest;
MD5Engine(const MD5Engine&);
MD5Engine& operator = (const MD5Engine&);
};
}
File Path.h:
#ifndef Foundation_Path_INCLUDED
#define Foundation_Path_INCLUDED
#include "Foundation.h"
#include <vector>
namespace Poco {
class Foundation_API Path
{
public:
enum Style
{
PATH_UNIX, /// Unix-style path
PATH_WINDOWS, /// Windows-style path
PATH_VMS, /// VMS-style path
PATH_NATIVE, /// The current platform's native style
PATH_GUESS /// Guess the style by examining the path
};
typedef std::vector<std::string> StringVec;
Path();
Path(const char* path);
Path(const std::string& path);
protected:
void parseUnix(const std::string& path);
void parseWindows(const std::string& path);
void parseVMS(const std::string& path);
void parseGuess(const std::string& path);
std::string buildUnix() const;
std::string buildWindows() const;
std::string buildVMS() const;
private:
std::string _node;
std::string _device;
std::string _name;
std::string _version;
StringVec _dirs;
bool _absolute;
};
There are three ways I know of to create an immutable object.
Method 1: internally immutable class members, internally and externally unmodifiable.
#ifndef INTERNALLY_IMMUTABLE_HPP
#define INTERNALLY_IMMUTABLE_HPP
#include <string>
class internally_immutable
{
public:
internally_immutable(const std::string & str)
: str_(str)
{
}
std::string get_str() const
{
return str_;
}
private:
const std::string str_;
};
#endif
Method 2: externally immutable class members, externally unmodifiable.
#ifndef EXTERNALLY_IMMUTABLE_HPP
#define EXTERNALLY_IMMUTABLE_HPP
#include <string>
#include <vector>
class externally_immutable
{
public:
externally_immutable(const std::string & str)
: str_(str)
{
}
std::string get_str() const
{
return str_;
}
private:
std::string str_;
};
#endif
Method 3: type immutable, partially externally unmodifiable, as someone could bypass your typedef.
#ifndef TYPED_IMMUTABLE_HPP
#define TYPED_IMMUTABLE_HPP
#include <string>
#include <vector>
typedef const typed_mutable typed_immutable;
class typed_mutable
{
public:
typed_mutable(const std::string & str)
: str_(str),
vec_()
{
}
void set_str(const std::string & str)
{
str_ = str;
}
std::string get_str() const
{
return str_;
}
private:
std::string str_;
};
#endif
What are the pros and cons of each immutable type? Compiler optimizations, impediments, usage of each type... Are there other ways of creating immutable objects in C++? What is the recommended, or most common way to create these immutable classes in C++?
you can make the immutable class when will you make your constructor private in this case your derived class can't access base class.
like as .
class externally_immutable
{
private :
externally_immutable(const std::string & str)
: str_(str){}
// to do
const string str_;
};
I get an error when try to call the function string SetToString(StringSet aSet); from an inherited class.
The header file for the base class:
#ifndef ITEM_H
#define ITEM_H
#include <ostream>
#include <set>
#include <string>
using namespace std;
typedef set<string> StringSet;
class Item
{
protected:
string title;
StringSet keywords;
public:
Item();
Item(const string& title, const string& keywords);
virtual ~Item();
void addKeywords(string keyword);
virtual ostream& print(ostream& out) const;
string getTitle() const;
string SetToString(StringSet aSet);
};
Implementation file for the base class :
#include "Item.h"
...
string Item::SetToString(StringSet aSet) {
string key;
int sizeCount = 0;
for (auto const& e : aSet) {
key += e;
sizeCount++;
if (sizeCount < aSet.size()) {
key += ", ";
}
}
SetToString(keywords);
return key;
}
...
When I try to do string k = SetToString(keywords); in the inherited class, I get the error : Error C2662 'std::string Item::SetToString(StringSet)': cannot convert 'this' pointer from 'const Book' to 'Item &'. How to fix this error, and why do I get it ?
Item::SetToString is not marked as const, so it cannot be called through a const pointer or reference, or on a const object.
You seem to be trying to call it from a function which is marked as const, and which therefore can't modify the current object (this) including by calling non-const functions on it.
Either make your inherited function not const, or make the base function const.
I’ve seen similar questions on StackOverflow, but none of them seems to apply to me.
Here is my code:
Option.cpp
#include "Option.h"
Option::Option(string valueName, string description, OptionType type){
this->valueName = valueName;
this->description = description;
this->type = type;
};
Option.h
#include <iostream>
using namespace std;
enum OptionType { FLAG, REQUIRED, NORMAL };
class Option {
string valueName, description, value;
OptionType type;
public:
Option(string valueName, string description, OptionType type);
void setValue(string value) {
this->value = value;
};
string getValueName() {
return this->valueName;
};
string getDescription() {
return this->description;
};
OptionType getType() {
return this->type;
};
};
Options.cpp
#include "Options.h"
using namespace std;
Options::Options(int _argc, const char * _argv[]) : argv(_argv) {
this->argc = _argc;
}
Options::~Options() {
options.~unordered_map();
}
void Options::printHelp() {
for (auto &i : options) {
cout << i.first << '\t' << i.second.getDescription() << '\n';
}
}
void Options::addFlag(string flagName, string description) {
}
void Options::addOption(string optionName, string valueName, string description, OptionType type) {
Option option(valueName, description, type);
options[optionName]=option;
}
void Options::addOptionAlias(string aliasName, string optionName) {
}
Options.h
#include <iostream>
#include <unordered_map>
#include "Option.h"
using namespace std;
class Options {
unordered_map<string, Option> options;
int argc;
const char ** argv;
public:
Options(int argc, const char * argv[]);
~Options();
void parse();
void addOption(string optionName, string valueName, string description, OptionType type);
void addFlag(string flagName, string description);
void addOptionAlias(string aliasName, string optionName);
void getOption(string optionName);
void printHelp();
};
It's in options.cpp on the line Option option(valueName, description, type); that the error seems to stem from, but for the life of me, I can’t figure out why. As far as I can see, the constructor in Option takes the right types.
The problem is actually in the next line:
options[optionName]=option;
That first calls the operator[] in the map, that searchs for the given key and returns the associated value. If the key is not found, it insert a default initialized value connected to that key. Then this value is copy assigned with your option.
Do you see the problem? Your Option class does not have a default constructor, so it cannot be default initialized! Read carefully your error message, surely it is talking about the default constructor, not the one you are looking at.
You have several solutions. The easiest would be to write a default constructor for your class.
The alternative would be never to use operator[] in the map so that the default constructor is never needed. If that's what you want to do, to insert an item you write:
options.insert(std::make_pair(optionName, option));
Finally, if you are using C++11 (or later) and a compliant enough compiler, you can even build the object directly into the container: zero copy overhead and you don't even need the copy constructor!
options.emplace(std::piecewise_construct,
std::forward_as_tuple(optionName),
std::forward_as_tuple(valueName, description, type));
There's a mismatch between the declaration of the constructor in the header and the definition in the source file.
In header...
Option(string& valueName, string& description, OptionType& type);
In source file...
Option::Option(string valueName, string description, OptionType type){
Notice the parameters are defined as references (e.g., string&) in the header, but as objects (e.g., string) in the source.
I am currently learning about classes and am having a problem in my class implementation file.
In my class header/specification file Book.h , I have the public member function setPages.
#ifndef BOOK_H
#define BOOK_H
#include <string>
#include "Author.h"
#include "Publisher.h"
class Book
{
private:
std::string _title;
std::string _edition;
int _pages;
int _copyrightYear;
Author _author;
Publisher _publisher;
public:
Book (std::string title, Author author, Publisher publisher)
{_title = title; _author = author; _publisher = publisher;}
void setPages (int pages);
void setCopyYear (int copyrightYear);
void setEdition (std::string edition);
std::string getTitle () const;
std::string getEditon () const;
int getPages () const;
int getCopyYear () const;
Author getAuthor () const;
Publisher getPublisher () const;
};
#endif
In my Book.cpp implementation file I have
#include <string>
#include "Author.h"
#include "Publisher.h"
#include "Book.h"
void Book::setPages (int pages)
{
_pages = pages;
}
I keep getting the error that Book is not a classname or namespace but I don't see what I've done wrong. I included my Book header file and checked to make sure everything was spelled correctly in the class. I've done the same thing in my other classes and it is working so I don't see why this isn't.
Any help appreciated thanks.
Here is Publisher.h and Author.h
#ifndef PUBLISHER_H
#define PUBLISHER_H
class Publisher
{
private:
std::string _name;
std::string _address;
std::string _phoneNumber;
public:
Publisher (std::string& name)
{_name=name;}
void setAddress (std::string address);
void setNumber (std::string phoneNumber);
std::string getAddress () const;
std::string getNumber () const;
bool operator==(std::string name)
{
if (_name == name)
return true;
else
return false;
};
#endif
and Author.H
#ifndef AUTHOR_H
#define AUTHOR_H
class Author
{
private:
std::string _name;
int _numberOfBooks;
public:
Author(std::string& name)
{_name = name;}
void setNumOfBooks (int numberOfBooks);
int getNoOfBooks () const;
bool operator==(std::string _name)
{
if (this->_name == _name)
return true;
else
return false;
}
};
#endif
Until #ahenderson decides to turn his comments into an answer:
bool operator==(std::string name) in "Publisher.h" is missing a brace in your example. is that actually in your code or a copy and paste error?
bool operator==(std::string name)
{
if (_name == name)
return true;
else
return false;
Oops, no brace here!
Suggestion: Simplify your operator== method:
The expression _name == name will already return true or false. No need to put it into an if clause that returns true or false.
Try this:
bool operator==(const std::string& name)
{
return (_name == name);
}
In the above example, the expression is evaluated and the result is returned, directly.
Also, you may run into compiler issues if your variables begin with an underscore, '_'. Change your naming convention so this issue doesn't raise its ugly head. Two common practices are to append a suffix, name_, or prefixing with something like m_name.