Simplest way to create class that behaves like stringstream - c++

I'm making a simple Error class that should be thrown using throw statement, logged or written in console. The basic idea of the usage is:
//const char* filename is function argument
if(!file_exists(filename))
throw Error(line, file, severity)<<"Invalid argument: the file does not exist: "<<filename;
I originally wanted to extend stringstream, but my searches indicate that it's impossible to extend on streams.
I'd really like to make the error class as convenient as you can see above, which means able to "eat" various types and append them to internal error message.

So actually it's not so hard. You can't inherit from stringstream directly - or I just didn't find out how. You'll soon drown in std template system...
template<class _Elem,
class _Traits,
class _Alloc>
// ... mom help me!
But, you can make a template:
template <class T>
Error& Error::operator<<(T const& value) {
//private std::stringstream message
message<<value;
//You can also trigger code for every call - neat, ain't it?
}
You'll be adding all values from this method to private variable within the class:
class Error
{
public:
Error(int, const char*, int);
~Error(void);
std::string file;
unsigned int line;
//Returns message.str()
std::string what();
//Calls message.operator<<()
template <class T>
Error& operator<< (T const& rhs);
private:
std::stringstream message;
};
There's still something I'm missing - how to distinguish between types supported by stringstream and others and throw error on the line of call, rather than in Error class. Also I'd like to write own handlers for unsupported types.

Related

C++ map template argument is invalid

I am trying to create a map for which the value is a class I have defined in another file; namely, FoodItemLookup. However, C++ is giving me the error:
template argument 1 is invalid
I find this odd, because I'm not using any templates.
I would appreciate it if someone could explain to me what I am doing wrong. I don't think I'm allowed to post all of the code, but here are the snippets in question:
The attempt at making a map:
std::map<string, FoodItemLookup> foodCatalogue;
A brief rundown of the FoodItemLookup.h file:
#ifndef FOODITEMLOOKUP
#define FOODITEMLOOKUP
#include <string>
class FoodItemLookup
{
private:
...
public:
//constructor
FoodItemLookup(std::string upc, int shelfLife, std::string name);
//copy constructor
FoodItemLookup(const FoodItemLookup &other);
//destructor
~FoodItemLookup();
...
);
#endif
You should have std:: in from of string in your first template argument:
std::map<std::string, FoodItemLookup> foodCatalogue;
"I find this odd, because I'm not using any templates."
Actually std::map uses templates. That's why you need to pass 2 types (here, std::string and FoodItemLookup) between the <> when instantiating your std::map.
More information on templates.

boost::program_options validation per argument instead of per argument type?

boost::program_options appears to support some level of custom validation but it seems odd to me that the validation is written in terms of types, and not per-argument, and I'm wondering if I'm missing something here.
For example, say you have a "file editing" program that takes input and output filenames from the command line. Next assume that you want to store these into variables of type boost::filesystem::path. Now, let's say we have a requirement that the input file must exist, but the output file doesn't (i.e. if the output file doesn't exist, we'll create it.) Ideally, we'd have a way to test that the input argument exists, and separately that the output file either exists and is writable or is in a directory that we can write to. (The specific differences here aren't actually relevant. This applies to any situation where you're using the same type in multiple places where you'd like to have different validation rules depending on the use.)
Because we configure validators by creating overrides of validate (which are presumably found at compile time by their type signatures, it appears we can only have one validator for all instances of boost::filesystem::path. I've seen the notify hook, but the signature of those callbacks has a const qualifier, so it doesn't seem like you could modify the value, and it's not clear in the documentation how throwing in a notify callback would get worked in to the validation system.
This seems like a pretty fundamental limitation to the point where I think I'm probably missing something. Am I? Thoughts?
It never hurts to have one type per concept in a program. If the two paths represent different concepts, give them their own types:
#include <iostream>
#include <cstdlib>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
namespace po = boost::program_options;
namespace fs = boost::filesystem;
template<class Type, class Tag>
struct tagged
{
Type const& get() const { return value_; }
Type& get() { return value_; }
operator Type& () { get(); }
friend decltype(auto) operator>>(std::istream& is, tagged& t) {
return is >> t.get();
}
friend decltype(auto) operator<<(std::ostream& os, tagged const& t) {
return os << t.get();
}
// and so on...
Type value_;
};
using bar_path = tagged<fs::path, class bar_path_tag>;
using foo_path = tagged<fs::path, class foo_path_tag>;
int main()
{
bar_path bar;
foo_path foo;
po::options_description desc("prog");
desc.add_options()
("foo", po::value(&foo), "a foo path")
("bar", po::value(&bar), "a bar path")
;
}
You can put per-option validation logic into a notifier callback.

Extend boost property tree get for own types

How do I extend boost property tree to support my own types?
e.g. I want to write
boost::property_tree::basic_ptree<std::string,std::string> xml;
...
xml.get<int>("level"),
xml.get<double>("accuracy"),
xml.get<Ship>("sauce_pan"),
...
And then I guess somewhere I'd like to describe how to get a Ship from a boost::property_tree::basic_ptree<std::string,std::string> or something similar.
You need to provide a default constructor for Ship and a stream input operator:
struct Ship {
friend std::istream& operator>>(std::istream& s, Ship& e) {
/* read ship data from s */
return s;
}
};
Unfortunately, I'm not sure if this is an official feature of property_tree as I can not find it in the documentation.
For more fine-grained access get also takes a Translator as it's second argument.
struct ShipTranslatorJSON {
// the type we return
typedef Ship external_type;
// the type expect as an argument
typedef std::string internal_type;
boost::optional< external_type > get_value(const internal_type&) {
return external_type();
}
// only required when you actually use put
// boost::optional< T > put_value(const T &);
};
// use as
xml.get<Ship>("sauce_pan", ShipTranslatorJSON());
This method also seems more "official", although nothing in the documentation actually explains what a Translator really is.

Call virtual function from another subclass

I've been set an assignment to create an rpn calculator that takes infix notation as input. So part of it is that it has to print out different stages of the process. So first it should separate a string into tokens and then store in a vector. Then it should convert this to rpn notation (e.g 3+4 -> 3 4 +) which is the part im stuck on now the part I'm stuck on now.
I've been recommended to use virtual abstract functions for this. So first I create a class with the abstract function. Then I create a subclass which converts a string to tokens stored in a string vector, this part works fine. Then I should create another subclass which converts the input string to rpn notation, therefore I have to call the function to convert to tokens at the start of this sub-class, this is the bit which I think is going wrong.
I have been given some code as a template and so far it's been very buggy so there might be something wrong with the syntax where the error is.
So I have this as my main class
template<typename T>
class tokenstream {
public:
virtual bool process(const std::string& input, std::vector<T>& output) = 0;
};
Then this as the first subclass
class tokenifier: public tokenstream<std::string> {
public:
bool process(const std::string& input, std::vector<std::string>& output) {
//this part works fine, ive tested it.
};
So then I have to create another subclass and then call the above function inside it, this is the part where it goes wrong.
class infix2rpn: public tokenstream<std::string> {
private:
tokenifier *tokens;
public:
tokenifier(tokenstream *_tokens): tokens(_tokens) {} //I think this line is the problem
bool process(const std::string& input, std::vector<std::string>& output) {
//call the underlying tokenstream object
std::vector<std::string> infixtokens;
if(!tokens->process(input, infixtokens))
{
return false;
}
return shunting_yard(infixtokens, output);
}
bool shunting_yard(const std::vector<std::string>& input, std::vector<std::string>& output){
//i've tested the shunting_yard algorithm and it works fine
}
};
When I try to compile it I get the error "ISO C++ forbids declaration of 'tokenifier' with no type [-fpermissive].
So the part I don't understand is how to call other virtual functions from another subclass.
Thanks
Your class is called infix2rpn, so its constructor should be named infix2rpn as well, not tokenifier. This has nothing to do with virtual functions.
Moreover, your attribute should be a tokenstream<std::string>*, not a tokenifier*, because you can't convert the tokenstream<std::string>* you get in the constructor to a tokenifier*.
tokenifier(tokenstream *_tokens): tokens(_tokens) {}
This was probably meant to be constructor, but in that case, the name of the method should be infix2rpn, same as the class name.
The error means, that you specified method tokenifier that has not specified return type, only constructors and destructors have no return type.
Note that void also specification of return type, in that case it means nothing returned.

Secure direct access to class members

I wonder if the following syntax can be "admitted" or if good practices consider this as coming from hell. The goal would be to add a level of protection to force the developer to be well-conscious of what he is doing. Here is the syntax :
class MyClass
{
public:
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return _writeStream;
}
inline const std::ofstream& writeStream() const
{
return _writeStream;
}
protected:
std::ofstream _writeStream;
};
The use would be :
x.writeStream().good(); // <- OK
x.writeStream().put('c'); // <- NOT OK
x.writeStream<true>().put('c'); // <- OK
I find this as a convenient way to tell to the developer : "Beware, you are using a low-level function and you have to be careful with what you are doing". Is it a "acceptable" way of providing a direct access to class members with a kind of "protection" ? Is there other way of coding a such thing ?
Have a look at meagar's comment:
You're making your code ugly, harder to maintain and inconvenient for... what exactly? Define your interface. That is the interface to your class. Do not allow developers to bypass it by using some ridiculous template flag hackery. If you're writing code, you always have to know what you're doing. Having to explicitly type <true> to indicate you especially know what you're doing is just... very, very wrong-headed. Developers have documentation. They don't need training wheels and artificial restrictions, they need clear concise code that lets them get things done. – meagar 2012-10-06 02:41:53Z
A class you provide to others should never be able to get into an unpredicted state when another user uses it. An unpredicted state is in this case a state which you never considered when you were writing the class. As such you should either never allow access to low-level methods of your class or document possible flaws.
Lets say you're writing a logger:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
private:
std::ofstream stream;
};
Ignore that there isn't a copy constructor and that the assignment operand is missing. Also ignore that it's a crude logger, it doesn't even provide a timestamp. However, as you can see, the state of the logger depends completely on the logger's methods, e.g. if the file has been successfully opened it won't be closed until the logger gets destroyed.
Now say that we use your approach:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return stream;
}
inline const std::ofstream& writeStream() const
{
return stream;
}
private:
std::ofstream stream;
};
And now someone uses the following code
logger.writeStream<true>.close();
Bang. Your logger is broken. Of course it's the users fault, since they used <true>, didn't they? But more often than not a user is going to copy example code, especially if he uses a library for the first time. The user sees your example
logger.writeStream().good(); // <- OK
logger.writeStream().put('c'); // <- NOT OK
logger.writeStream<true>().put('c'); // <- OK
and ignores the documentation completely at first. Then he's going to use the first and the last version. Later he discovers that the last version works every time! What a miraculous thing <true> is. And then he starts to blame you for evil things that happen, so you have protect yourself from blatant flames with a documentation which includes a warning:
/**
* \brief Returns a reference to the internal write stream
*
* \note You have to use the template parameter `<true>` in order to use it
*
* \warning Please note that this will return a reference to the internal
* write stream. As such you shouldn't create any state in which
* the logger cannot work, such as closing the stream.
*/
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return stream;
}
So, what did we get? We still had to put that warning somewhere. It would have been much simpler if we made stream public:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
/**
* The internal write stream. Please look out that you don't create
* any state in which the logger cannot work, such as closing the stream.
*/
std::ofstream stream;
};
or sticked to
/** >put warning here< */
inline std::ofstream & writeStream()
{
return stream;
}
Woops. So either don't allow access to your low-level methods (build a wrapper to specific std::ofstream methods if they should be allowed to use them) or document the possible flaws which can happen if you alter the object's internals to much, but don't go the middle-way and make it look okay with a static_assert.