I'm making a simple logging class with a pointer to either a std::ofstream or std::cerr.
Is there any simple way to use a smart pointer for auto clean-up regardless of which stream is used?
The code must compile on clang++, g++, and VS2013.
Code
#include <iostream>
#include <fstream>
#include <string>
class Logger {
private:
std::ostream * output_stream{ nullptr };
bool using_file{ false };
public:
Logger()
{
output_stream = &std::cerr;
using_file = false;
}
Logger(std::string file)
{
output_stream = new std::ofstream(file);
using_file = true;
}
~Logger()
{
if (using_file)
{
delete output_stream;
}
}
template<typename T>
void log(T info)
{
*output_stream << info << std::endl;
}
};
class tmp {
int i{ 4 };
friend std::ostream & operator<<(std::ostream &os, const tmp& p);
};
std::ostream &operator<<(std::ostream &os, const tmp& p)
{
return os << p.i;
}
int main()
{
tmp t;
Logger logger;
logger.log(t);
system("pause");
return 0;
}
Attempts
std::unique_ptr
I can use std::unique_ptr for the file like so:
std::unique_ptr<std::ostream> p;
p = std::make_unique<std::ofstream>("file.txt");
*p << "hi there" << std::endl;
Trying this with std::cout warns me about a deleted function (assuming that's the constructor.
std::unique_ptr<std::ostream> p2;
p2 = std::make_unique<std::ostream>(std::cout);
*p2 << "hey" << std::endl;
std::shared_ptr
Because std::unique_ptr is only for owning things, and std::cout shouldn't be owned, I thought I'd try std::shared_ptr
std::shared_ptr<std::ostream> p;
p = std::make_shared<std::ostream>(std::cout);
*p << "hola" << std::endl;
It gives me the same deleted constructor error. p = &std::cout complains about a type mismatch, so it's also not working.
You can use a shared_ptr with a deleter that does not delete anything in the case of cerr and just a normally constructed shared_ptr in the case of ofstream
class Logger {
private:
std::shared_ptr<std::ostream> output_stream{ nullptr };
public:
Logger() :
output_stream(&std::cerr, [](std::ostream*){})
{ }
Logger(std::string file) :
output_stream(std::make_shared<std::ofstream>(file))
{ }
// default destructor is OK
template<typename T>
void log(T info)
{
*output_stream << info << std::endl;
}
};
I would just have two pointers, one smart and one raw.
The raw pointer is always used to refer to the stream. The smart pointer is just used for clean-up if needed.
class Logger {
private:
std::unique_ptr<std::ofstream> file_stream;
std:ostream *stream;
public:
Logger() : stream(&std::cerr) {}
Logger(const std::string& file)
: file_stream(std::make_unique<std::ofstream>(file)), stream(file_stream.get()){}
template<typename T>
void log(T info) {
*stream << info << std::endl;
}
};
I tend to try to avoid cases where I want an object to "own" such things. In the times I did not have much choice, I ended up settling with a "shouldDelete" flag or a callback.
class Logger {
public:
Logger(std::ofstream *outputStream, bool deleteOutputStream)
: outputStream(outputStream), deleteOutputStream(deleteOutputStream)
{ }
~Logger()
{
if (deleteOutputStream) delete outputStream;
}
};
Logger logger(&std::cout, false);
class Logger {
public:
typedef std::function<void(std::ostream*)> Deleter;
typedef std::unique_ptr<std::ostream, Deleter> OStreamPointer;
Logger(OStreamPointer &&outputStream)
: outputStream(std::move(outputStream))
{ }
~Logger() { }
private:
OStreamPointer outputStream;
};
Logger logger(Logger::OStreamPointer(
&std::cout,
[](std::ostream*) {})); //no-op callback
You could do this by releasing the smart pointer in the destructor (and elsewhere) in the cases where it shouldn't be deleted, but that's not worth the hassle IMO.
Instead, I'd recommend simply using two pointers: one for streams that need to be managed and one for those that don't:
class Logger {
private:
std::ostream * unmanaged_stream{ nullptr };
std::unique_ptr<std::ostream> managed_stream{ nullptr };
bool using_file{ false };
std::ostream& output_stream()
{
return using_file ? *managed_stream : *unmanaged_stream;
}
public:
Logger()
: unmanaged_stream{&std::cerr},
using_file{false}
{
}
Logger(const std::string& file)
: managed_stream{std::make_unique<std::ofstream>(file)},
using_file{true}
{
}
template<typename T>
void log(T info)
{
output_stream() << info << std::endl;
}
};
If saving space is a priority you could put them in a union, but then you'd have to explicitly call the destructor and placement new to define the active member, which again is more hassle and probably not worth it.
Related
I need to write a program that output either to the std::cout or to some file. I was reading this post to see how to do. However I would like to separate the management of the ostream from the main. So I was thinking to write a class, but I'm a bit confused about the design. I have in mind two solution
(publicly) Subclass ostream: it this way I would have all method of ostream. However here the main problem would be the creator:
class sw_ostream : public ostream {
sw_ostream (cost char* filename) : ostream ( \\? ) {
\\ ...
}
\\...
}
because I should initialize ostream depending on filename, and apparently is impossible.
Create a class having osteram as a member and overload operator<<.
I'm sure that there are other, more elegant solution to this problem. Which design would you suggest?
I would try to split here the stream creation with the stream usage. std::ostream is already polymorphic, so as long as you pass a reference or pointer to the function that uses the stream, all good.
For the creation, I would go for creating the stream in the heap, as the post you linked to suggests. However, doing explicit memory management (raw new/delete) is dangerous, so I would use a smart pointer, like std::unique_ptr:
#include <fstream>
#include <memory>
struct ConditionalDeleter
{
bool must_delete;
void operator()(std::ostream* os) const { if (must_delete) delete os; }
};
using OstreamPtr = std::unique_ptr<std::ostream, ConditionalDeleter>;
OstreamPtr create_stream(bool to_file)
{
if (to_file)
return OstreamPtr { new std::ofstream {"myfile.txt"}, ConditionalDeleter {true} };
else
return OstreamPtr { &std::cout, ConditionalDeleter {false} };
}
void use_stream(std::ostream& os)
{
os << "Hello world!" << std::endl;
}
int main()
{
auto streamptr = create_stream(false);
use_stream(*streamptr);
}
I've used a custom deleter with std::unique_ptr. The reason for that is: if we are using the file, I want the stream to be deleted; but std::cout is a global object, which we must not delete. The agreement here is that when your OstreamPtr gets destroyed, ConditionalDeleter::operator() will get called. *streamptr returns you a reference to your std::ostream, which you can use as you want.
Please note you need C++11 support to use this solution.
Since they both inherit from std::ostream, you can just assign it to a std::ostream&.
In your case, you can simply do something like this:
#include <iostream>
#include <fstream>
void do_stuff(const char* filename = nullptr) {
std::ofstream _f;
std::ostream& os = filename ? (_f.open(filename), _f) : std::cout;
os << "Output normally";
// If you want to check if it is a file somewhere else
if (std::ofstream* fp = dynamic_cast<std::ofstream*>(&os)) {
std::ofstream& f = *fp;
// But here you can probably check the condition used to make the file
// (e.g. here `filename != nullptr`)
}
// After returning, `os` is invalid because `_f` dies, so you can't return it.
}
A simpler approach would be to not worry about this at all. Just put all of your code that outputs stuff inside one function that takes a std::ostream& parameter, and call it with a std::ofstream or another std::ostream:
void do_stuff(std::ostream& os) {
os << "Write string\n";
}
int main() {
if (using_file) {
std::ofstream f("filename");
do_stuff(f);
} else {
do_stuff(std::cout);
}
}
If you want to be able to return the object without the file closing and becoming a dangling reference, you need to store it somewhere. This example stores it in a struct:
#include <iostream>
#include <fstream>
#include <utility>
#include <new>
#include <cassert>
struct sw_ostream {
private:
// std::optional<std::fstream> f;
// Use raw storage and placement new pre-C++17 instead of std::optional
alignas(std::fstream) unsigned char f[sizeof(std::fstream)];
std::ostream* os;
bool did_construct_fstream() const noexcept {
// If `os` is a pointer to `f`, we placement new`d, so we need to destruct it
return reinterpret_cast<unsigned char*>(os) == f;
}
// Destroys currently held std::fstream
// (Must have been constructed first and have `os` point to it)
void destruct() noexcept {
static_cast<std::fstream&>(*os).~basic_fstream();
}
public:
sw_ostream() = default;
sw_ostream(std::ostream& os_) : os(&os_) {}
template<class... Args>
explicit sw_ostream(Args&&... args) {
os = new (f) std::fstream(std::forward<Args>(args)...);
}
sw_ostream(std::fstream&& f) : os(nullptr) {
*this = std::move(f);
}
sw_ostream(sw_ostream&& other) noexcept {
*this = std::move(other);
}
sw_ostream& operator=(sw_ostream&& other) {
if (did_construct_fstream()) {
if (other.did_construct_fstream()) {
static_cast<std::fstream&>(*os) = std::move(static_cast<std::fstream&>(*(other.os)));
} else {
destruct();
os = other.os;
}
} else {
if (other.did_construct_fstream()) {
os = new (f) std::fstream(std::move(static_cast<std::fstream&>(*other.os)));
} else {
os = other.os;
}
}
return *this;
}
sw_ostream& operator=(std::ostream& other) {
if (did_construct_fstream()) {
destruct();
}
os = &other;
return *this;
}
sw_ostream& operator=(std::fstream&& other) {
if (did_construct_fstream()) {
static_cast<std::fstream&>(*os) = std::move(other);
} else {
os = new (f) std::fstream(std::move(other));
}
return *this;
}
std::ostream& operator*() const noexcept {
return *os;
}
std::ostream* operator->() const noexcept {
return os;
}
operator std::ostream&() const noexcept {
return *os;
}
std::fstream* get_fstream() const noexcept {
if (did_construct_fstream()) return &static_cast<std::fstream&>(*os);
return dynamic_cast<std::fstream*>(os);
}
// `s << (...)` is a shorthand for `*s << (...)` (Where `s` is a `sw_ostream`)
template<class T>
const sw_ostream& operator<<(T&& o) const {
*os << std::forward<T>(o);
return *this;
}
template<class T>
sw_ostream& operator<<(T&& o) {
*os << std::forward<T>(o);
return *this;
}
~sw_ostream() {
if (did_construct_fstream()) {
destruct();
}
}
};
int main() {
sw_ostream s;
if (opening_file) {
s = std::fstream("filename");
} else {
s = std::cout;
}
if (std::fstream* fp = s.get_fstream()) {
assert(fp->is_open());
}
s << "Hello, world!\n";
s->flush();
}
I also came up with another solution that uses std::unique_ptr so that you can use any derived class of std::ostream, but that unnecessarily uses dynamic memory if you only want an existing std::ostream (Like std::cout) or a std::fstream. See here.
Is it possible to automatically wrap a value in a temporary whose lifetime extends across the entire statement?
Originally I hoped a solution or alternative to my problem would present itself while writing the details for the question, unfortunately that didn't happen, so...
I have an abstract base class Logger that provides a streaming-like interface for generating log statements. Given an instance logger of this class, I want the following to be possible:
logger << "Option " << variable << " is " << 42;
Unlike regular streams, which simply generate a string from all the components (4 components in the example above), I want to generate an instance of a class Statement that manages a linked list of all the statement's components. The entire statement is then passed via pure virtual method to a class derived from Logger, which can iterate over all the components of the statement and do whatever with them, including obtaining information about their type, retrieving their value, or converting them to a string.
The tricky bit: I want to do the above without dynamic memory allocations. This means that every component of the statement must be wrapped by a temporary type that links the components into a traversable list, within the scope of the statement!
I posted a working example on ideone, with one problem: every component needs to be wrapped by a function call in order to generate an instance of the temporary type. The log statement therefore ends up looking like this:
logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);
All my attempts to get rid of the wrap function (e.g., using an implicit converting constructor for the component), have failed thus far, therefore this question.
How can the components of the log statement automatically be wrapped in their component type (e.g., using a converting constructor for the component), without the need for an explicit call to a wrapping function?
Alternatively, I would appreciate suggestions for other ways that achieve the same effect, i.e., allowing iteration over the components of the log statement in a class derived from logger, without dynamic memory allocations.
Reference: Full code on ideone:
#include <iostream>
#include <sstream>
struct Statement;
struct Logger;
struct ComponentBase;
//------------------------------------------------------------------------------
struct ComponentBase {
mutable ComponentBase *next;
ComponentBase() : next(nullptr) { }
virtual std::string toString() = 0;
};
template <typename T>
struct Component : ComponentBase {
T value;
Component(T value) : value(value) { }
~Component() { }
virtual std::string toString() {
std::stringstream ss;
ss << value;
return ss.str();
}
};
struct ComponentIterator {
ComponentBase *ptr;
ComponentIterator(ComponentBase *ptr) : ptr(ptr) { }
ComponentBase &operator*() { return *ptr; }
void operator++() { ptr = ptr->next; }
bool operator!=(ComponentIterator &other) { return (ptr != other.ptr); }
};
//------------------------------------------------------------------------------
struct Statement {
Logger *logger;
ComponentBase *front;
ComponentBase *back;
ComponentIterator begin() { return front; }
ComponentIterator end() { return nullptr; }
template <typename T>
Statement(Logger &logger, Component<T> &component)
: logger(&logger), front(&component), back(&component) { }
~Statement();
template <typename T>
Statement &operator<<(Component<T> &&component) {
back->next = &component;
back = &component;
return *this;
}
};
//------------------------------------------------------------------------------
struct Logger {
template <typename T>
Statement operator<<(Component<T> &&component) {
return {*this, component};
}
virtual void log(Statement &statement) = 0;
};
Statement::~Statement() {
logger->log(*this);
}
//------------------------------------------------------------------------------
template <typename T>
Component<T const &> wrap(T const &value) {
return value;
}
template <size_t N>
Component<char const *> wrap(char const (&value)[N]) {
return value;
}
//------------------------------------------------------------------------------
struct MyLogger : public Logger {
virtual void log(Statement &statement) override {
for(auto &&component : statement) {
std::cout << component.toString();
}
std::cout << std::endl;
}
};
int main() {
std::string variable = "string";
MyLogger logger;
logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);
}
I have some crazy but working solution.
Having component implemented like this you will get rid of templates all over your code:
struct Component
{
mutable Component *next;
typedef std::function<std::string()> ToStringFunction;
ToStringFunction toString; // <-- 1
template<typename T>
Component(const T& value)
: next(nullptr),
toString(nullptr)
{
toString = [&value](){
std::stringstream ss;
ss << value;
return ss.str();
};
}
};
Where (1) is the unction that knows what to do. This member std::function is a space for optimization.
And the rest of the code should look like:
struct ComponentIterator {
Component *ptr;
ComponentIterator(Component *ptr) : ptr(ptr) { }
Component &operator*() { return *ptr; }
void operator++() { ptr = ptr->next; }
bool operator!=(ComponentIterator &other) { return (ptr != other.ptr); }
};
//------------------------------------------------------------------------------
struct Statement {
Logger *logger;
Component *front;
Component *back;
ComponentIterator begin() { return front; }
ComponentIterator end() { return nullptr; }
Statement(Logger &logger, Component &component)
: logger(&logger), front(&component), back(&component) { }
~Statement();
Statement &operator<<(Component &&component) {
back->next = &component;
back = &component;
return *this;
}
};
//------------------------------------------------------------------------------
struct Logger {
Statement operator<<(Component &&component) {
return{ *this, component };
}
virtual void log(Statement &statement) = 0;
};
Statement::~Statement() {
logger->log(*this);
}
//------------------------------------------------------------------------------
struct MyLogger : public Logger {
virtual void log(Statement &statement) override {
for (auto &&component : statement) {
std::cout << component.toString();
}
std::cout << std::endl;
}
};
int main() {
std::string variable = "string";
MyLogger logger;
//logger << wrap("Option ") << wrap(variable) << wrap(" is ") << wrap(42);
logger << 42;
logger << variable << " is " << 42;
logger << "Option " << variable << " is " << 42;
}
this will print:
42
string is 42
Option string is 42
UPD
as dyp advised here is alternative implementation of the Component structure without lambda:
struct Component
{
mutable Component *next;
void* value;
std::string toString(){
return _toString(this);
}
template<typename T>
Component(const T& inValue)
: next(nullptr),
value((void*)&inValue),
_toString(toStringHelper<T>)
{}
private:
typedef std::string(*ToStringFunction)(Component*);
ToStringFunction _toString;
template<typename T>
static std::string toStringHelper(Component* component)
{
const T& value = *(T*)component->value;
std::stringstream ss;
ss << value;
return ss.str();
}
};
I propose a solution tuple based:
template <class... Ts> class streamTuple;
struct Logger {
template <typename T>
streamTuple<T> operator<<(const T& t);
template <typename Tuple, std::size_t ... Is>
void dispatch(const Tuple& tup, std::index_sequence<Is...>)
{
int dummy[] = {0, (void(std::cout << std::get<Is>(tup) << " "), 0)...};
static_cast<void>(dummy); // Avoid unused variable warning
}
// Logger can take generic functor to have specific dispatch
// Or you may reuse your virtual method taking ComponentBase.
};
template <class... Ts> class streamTuple
{
public:
streamTuple(Logger* logger, const std::tuple<Ts...>& tup) :
logger(logger), tup(tup) {}
streamTuple(streamTuple&& rhs) : logger(rhs.logger), tup(std::move(rhs.tup))
{
rhs.logger = nullptr;
}
~streamTuple()
{
if (logger) {
logger->dispatch(tup, std::index_sequence_for<Ts...>());
}
}
template <typename T>
streamTuple<Ts..., const T&> operator << (const T& t) &&
{
auto* moveddLogger = logger;
logger = nullptr;
return {moveddLogger, std::tuple_cat(tup, std::tie(t))};
}
private:
Logger* logger;
std::tuple<Ts...> tup;
};
template <typename T>
streamTuple<T> Logger::operator<<(const T& t) {
return {this, t};
}
Demo
And usage:
int main() {
Logger log;
std::string variable = "string";
log << variable << 42 << "hello\n";
}
I have the following code with a custom Variant class and a custom SmartPtr class:
using namespace std;
class Object
{
public:
};
template<typename T>
class SmartPtr
{
public:
template<typename Y>
explicit SmartPtr(Y* p) { p_ = p; }
SmartPtr(std::nullptr_t) { p_ = nullptr; }
private:
T* p_;
};
class Variant
{
public:
Variant(bool b) : _b(b) { }
private:
bool _b;
};
class Obj
{
public:
void test(SmartPtr<Object> /*p*/) { cout << "smartptr version!" << endl; }
void test(Variant /*v*/) { cout << "variant version!" << endl; }
};
int main(int argc, const char *argv[])
{
Obj o;
o.test(nullptr); // calls SmartPtr version
o.test(true); // calls Variant version
o.test(false); // -> compiler error: ambiguous call to overloaded function
return 0;
}
I assume that the boolean false can be converted both to the Variant and to 0 then to nullptr and then to SmartPtr, which causes this error.
Any chances of avoiding this conversion?
For the user of the library an API which works with 'o.test(true);' but requires something like 'o.test(Variant(false));' to compile is not very intuitive.
I believe I have an ideal solution. It only requires that the test function be altered, so it leaves SmartPtr and Variant alone, which is ideal. It adds a non-defined templated overload to test that has specializations for bool and nullptr that are defined. This directly dispatches bool and nullptr to the desired specialization, but causes link errors on other unhandled types. I'm so glad to have this worked out because I've certainly run into this in many forms myself. I wish you could use explicit of function parameters!!
I got the idea from here: C++ templates that accept only certain types
using namespace std;
class Object
{
public:
};
class Variant
{
public:
Variant( bool b) : _b(b) { }
private:
bool _b;
};
template<typename T>
class SmartPtr
{
public:
SmartPtr(std::nullptr_t null) { p_ = nullptr; }
template<typename Y>
SmartPtr(Y* p) { p_ = p; }
private:
T* p_;
};
class Obj
{
public:
void test(SmartPtr<Object> here /*p*/) {
cout << "smartptr version!" << endl;
}
void test(Variant /*v*/) { cout << "variant version!" << endl; }
template<typename T> void test(T t);
template<>
void test<bool>(bool b) {
cout << "bool specialization" << endl;
test(Variant(b));
}
template<>
void test<std::nullptr_t>(std::nullptr_t null) {
cout << "nullptr specialization" << endl;
test(SmartPtr<Object>(nullptr));
}
};
int main(int argc, const char *argv[])
{
Obj o;
Obj c;
Object object;
//o.test(3); // Gives link error LNK2019
o.test(Variant(true)); // calls Variant version
o.test(SmartPtr<Object>(&object)); // calls SmartPtr version
o.test(nullptr); // dispatched to SmartPtr version by nullptr specialization
o.test(true); // dispatched to Variant version by bool specialization
o.test(false); // dispatched to Variant version by bool specialization
return 0;
}
I had already answered with something not ideal, so I leave that answer in tact as what follows:
=============================================
I don't have an ideal solution here, and I don't know the constraints you have on your code so this may not be of functional use to you, but the following is sensible. It disallows code to use nullptr at compile time and relies on a global null_smart constant to be used in all cases where the caller is simply showing no interest in passing an object.
#include <iostream>
using namespace std;
class Object
{
public:
};
class Variant
{
public:
Variant(bool b) : _b(b) { }
private:
Variant(std::nullptr_t) {};
private:
bool _b;
};
template<typename T>
class SmartPtr
{
public:
SmartPtr() { p_ = nullptr; }
template<typename Y>
SmartPtr(Y* p) { p_ = p; }
private:
T* p_;
};
class Obj
{
public:
void test(SmartPtr<Object> /*p*/) { cout << "smartptr version!" << endl; }
void test(Variant /*v*/) { cout << "variant version!" << endl; }
};
const SmartPtr<Object> null_smart;
int main(int argc, const char *argv[])
{
Obj o;
o.test(null_smart); // calls SmartPtr version, without interest in passing object
o.test(true); // calls Variant version
o.test(false); // calls Variant version
return 0;
}
It's cleaner than the true/Variant(false) issue, but still a bit on the picky side.
I have a finite amount of classes with the nearly-same implementation, the only different being the underlying type of data they manipulate:
class IntContainer
{
public:
void setData(int data);
int getData();
int _data;
};
class BoolContainer
{
public:
void setData(bool data);
bool getData();
bool _data;
};
class StringContainer
{
public:
void setData(std::string data);
std::string getData();
std::string _data;
};
// Etc. You get the idea.
I'd like to reduce the code duplication of these classes by using templates like so:
template<typename T>
class GenericContainer
{
public:
void setData(T data);
T getData();
T _data;
};
And specialization:
typedef GenericContainer<int> IntContainer;
typedef GenericContainer<bool> BoolContainer;
typedef GenericContainer<std::string> StringContainer;
This works well. But I'd also like to add an abstract base class to these specialized classes to be able to manipulate them in a generic way (eg. in a collection). The problem is this base class should have the getData and setData methods to be able to call them even without knowing the dynamic type of the object manipulated.
I would implement it with something like this:
class Base
{
public:
virtual void setData(??? data) = 0;
virtual ??? getData() = 0;
};
// Modify GenericContainer's definition like so
template<typename T>
class GenericContainer : Base { ... }
And use it somehow like that:
int main(int argc, char const *argv[])
{
IntContainer intc = IntContainer();
intc.setData(42);
std::cout << intc.getData() << std::endl;
BoolContainer boolc = BoolContainer();
boolc.setData(false);
std::cout << boolc.getData() << std::endl;
std::vector<Base> v;
v.push_back(intf);
v.push_back(boolf);
for (std::vector<Base>::iterator it = v.begin() ; it != v.end(); ++it)
std::cout << it->getData() << std::endl;
return 0;
}
The problem is I don't know how to write the Base methods prototypes as the type is unknow (and does not matter, the derived class implementation should be called at runtime based on the dynamic type of the object).
TL;DR: How to implement an abstract base class over several fully specialized templated classes ?
There is simply no way to do what you want.
The problem is, if this was allowed, the compiler would have to generate as many virtual methods in the base class as there are possible specializations of the template child class (ie. an infinity) which is not possible.
How about making base template too? Of course there is no way you can do something like
std::vector<Base> v;
v.push_back(intf);
v.push_back(boolf);
but the rest you can achieve with something simple as
template<typename T>
class Base
{
public:
virtual void setData(T data) = 0;
virtual T getData() = 0;
};
// Modify GenericContainer's definition like so
template<typename T>
class GenericContainer : Base<T> {
T d;
public:
virtual void setData(T data) {d = data;}
virtual T getData() { return d; }
};
You can use it in any way as long as types match.
IntContainer intc = IntContainer();
intc.setData(42);
std::cout << intc.getData() << std::endl;
BoolContainer boolc = BoolContainer();
boolc.setData(true);
std::cout << boolc.getData() << std::endl;
std::vector<IntContainer> v;
v.push_back(intc);
// v.push_back(boolc); No can't do.
This is a solution for any types of classes that can round-trip through a stringstream, and such conversion is the right way to convert between types. It isn't efficient at all:
struct BaseContainer {
protected:
boost::any data;
std::function< std::string( boost::any const& ) > toString;
virtual void setDataAny( boost::any x, std::function< std::string( boost::any const& ) > convert ) {
data = x;
toString = convert;
}
public:
virtual boost::any getDataAny() const {
return data;
}
template<typename T>
void setData( T const& t ) {
setDataAny( boost::any(t), []( boost::any const& a )->std::string {
std::string retval;
std::stringstream ss;
try
{
ss << boost::any_cast< T >(a);
ss >> retval;
return retval;
} catch(const boost::bad_any_cast &) {
return retval;
}
});
};
template<typename T>
struct TypedContainer:BaseContainer {
public:
T getData() const {
T retval;
try {
retval = boost::any_cast<T>(getDataAny());
return retval;
} catch(const boost::bad_any_cast &) {
std::string str = toString( getDataAny() );
std::stringstream ss;
ss << str;
ss >> retval;
return retval;
}
}
};
with fewer types, you could do something similar, so long as you have conversion functions between them.
Alternatively, if you like exceptions, you could throw.
Alternatively, you could use boost::variants, which do no conversions, but work from a finite list of types (they are basically tagged unions that support more types than C++03 lets union do, and with some nice semantics on assign/copy/etc).
Assuming you have some design flexibility, you can change your interface to accommodate this, although its not as efficient as an infinite virtual table
You can set values through construction, or >>
You can get values through <<
Your vector needs to be a base pointer or reference, the size of each base object is variable, the pointer, explicit or implicit through a reference is of fixed size
Notice that copies are more efficient if the compiler knows that it is copying from one generic to another as opposed to base to base
#include <iostream>
#include <sstream>
#include <vector>
class gen_base
{
public:
virtual std::ostream & output(std::ostream& S) const = 0;
virtual std::istream & input(std::istream& S) = 0;
friend std::istream & operator >> (std::istream &S, gen_base &g) {
return g.input(S);
}
friend std::ostream & operator << (std::ostream &S, const gen_base &g) {
return g.output(S);
}
};
template<typename T>
class GenericContainer : public gen_base
{
public:
GenericContainer(T data) : _data(data) {}
GenericContainer(const gen_base& other) {
// std::cout << "EXPENSIVE" << std::endl;
std::stringstream cvt;
other.output(cvt);
input(cvt);
}
template <class U>
GenericContainer(const GenericContainer<U>& other)
{
// std::cout << "CHEAP" << std::endl;
_data=other.getData();
}
virtual std::istream & input(std::istream &S) {
return (S >> _data);
}
virtual std::ostream & output(std::ostream &S) const {
return (S << _data);
}
T getData() const {
return _data;
}
private:
T _data;
};
typedef GenericContainer<int> IntContainer;
typedef GenericContainer<bool> BoolContainer;
typedef GenericContainer<std::string> StringContainer;
int main(int argc, char const *argv[])
{
IntContainer * intc = new IntContainer(42);
std::cout << *intc << std::endl;
gen_base * boolc = new BoolContainer(*intc);
std::cout << *boolc << std::endl;
IntContainer * intc2 = new IntContainer(*boolc);
std::cout << *intc2 << std::endl;
std::vector<gen_base *> v; // has to be pointer to base;
v.push_back(intc);
v.push_back(boolc);
v.push_back(intc2);
for (std::vector<gen_base *>::iterator it = v.begin() ; it != v.end(); ++it)
std::cout << **it << std::endl;
delete intc;
delete boolc;
return 0;
}
My use is pretty complicated. I have a bunch of objs and they are all passed around by ptr (not reference or value unless its an enum which is byval). At a specific point in time i like to call CheckMembers() which will check if each member has been set or is null. By default i cant make it all null because i wouldnt know if i set it to null or if it is still null bc i havent touch it since the ctor.
To assign a variable i still need the syntax to be the normal var = p; var->member = new Type;. I generate all the classes/members. So my question is how can i implement a property like feature where i can detect if the value has been set or left as the default?
I am thinking maybe i can use C++ with CLR/.NET http://msdn.microsoft.com/en-us/library/z974bes2.aspx but i never used it before and have no idea how well it will work and what might break in my C++ prj (it uses rtti, templates, etc).
Reality (edit): this proved to be tricky, but the following code should handle your requirements. It uses a simple counter in the base class. The counter is incremented once for every property you wish to track, and then decremented once for every property that is set. The checkMembers() function only has to verify that the counter is equal to zero. As a bonus, you could potentially report how many members were not initialized.
#include <iostream>
using namespace std;
class PropertyBase
{
public:
int * counter;
bool is_set;
};
template <typename T>
class Property : public PropertyBase
{
public:
T* ptr;
T* operator=(T* src)
{
ptr = src;
if (!is_set) { (*counter)--; is_set = true; }
return ptr;
}
T* operator->() { return ptr; }
~Property() { delete ptr; }
};
class Base
{
private:
int counter;
protected:
void TrackProperty(PropertyBase& p)
{
p.counter = &counter;
counter++;
}
public:
bool checkMembers() { return (counter == 0); }
};
class OtherObject : public Base { }; // just as an example
class MyObject : public Base
{
public:
Property<OtherObject> x;
Property<OtherObject> y;
MyObject();
};
MyObject::MyObject()
{
TrackProperty(x);
TrackProperty(y);
}
int main(int argc, char * argv[])
{
MyObject * object1 = new MyObject();
MyObject * object2 = new MyObject();
object1->x = new OtherObject();
object1->y = new OtherObject();
cout << object1->checkMembers() << endl; // true
cout << object2->checkMembers() << endl; // false
delete object1;
delete object2;
return 0;
}
There are a number of ways to do this, with varying tradeoffs in terms of space overhead. For example, here's one option:
#include <iostream>
template<typename T, typename OuterClass>
class Property
{
public:
typedef void (OuterClass::*setter)(const T &value);
typedef T &value_type;
typedef const T &const_type;
private:
setter set_;
T &ref_;
OuterClass *parent_;
public:
operator value_type() { return ref_; }
operator const_type() const { return ref_; }
Property<T, OuterClass> &operator=(const T &value)
{
(parent_->*set_)(value);
return *this;
}
Property(T &ref, OuterClass *parent, setter setfunc)
: set_(setfunc), ref_(ref), parent_(parent)
{ }
};
struct demo {
private:
int val_p;
void set_val(const int &newval) {
std::cout << "New value: " << newval << std::endl;
val_p = newval;
}
public:
Property<int, demo> val;
demo()
: val(val_p, this, &demo::set_val)
{ }
};
int main() {
demo d;
d.val = 42;
std::cout << "Value is: " << d.val << std::endl;
return 0;
}
It's possible to get less overhead (this has up to 4 * sizeof(void*) bytes overhead) using template accessors - here's another example:
#include <iostream>
template<typename T, typename ParentType, typename AccessTraits>
class Property
{
private:
ParentType *get_parent()
{
return (ParentType *)((char *)this - AccessTraits::get_offset());
}
public:
operator T &() { return AccessTraits::get(get_parent()); }
operator T() { return AccessTraits::get(get_parent()); }
operator const T &() { return AccessTraits::get(get_parent()); }
Property &operator =(const T &value) {
AccessTraits::set(get_parent(), value);
return *this;
}
};
#define DECL_PROPERTY(ClassName, ValueType, MemberName, TraitsName) \
struct MemberName##__Detail : public TraitsName { \
static ptrdiff_t get_offset() { return offsetof(ClassName, MemberName); }; \
}; \
Property<ValueType, ClassName, MemberName##__Detail> MemberName;
struct demo {
private:
int val_;
struct AccessTraits {
static int get(demo *parent) {
return parent->val_;
}
static void set(demo *parent, int newval) {
std::cout << "New value: " << newval << std::endl;
parent->val_ = newval;
}
};
public:
DECL_PROPERTY(demo, int, val, AccessTraits)
demo()
{ val_ = 0; }
};
int main() {
demo d;
d.val = 42;
std::cout << "Value is: " << (int)d.val << std::endl;
return 0;
}
This only consumes one byte for the property struct itself; however, it relies on unportable offsetof() behavior (you're not technically allowed to use it on non-POD structures). For a more portable approach, you could stash just the this pointer of the parent class in a member variable.
Note that both classes are just barely enough to demonstrate the technique - you'll want to overload operator* and operator->, etc, as well.
Here's my temporary alternative. One that doesn't ask for constructor parameters.
#include <iostream>
#include <cassert>
using namespace std;
template <class T>
class Property
{
bool isSet;
T v;
Property(Property&p) { }
public:
Property() { isSet=0; }
T operator=(T src) { v = src; isSet = 1; return v; }
operator T() const { assert(isSet); return v; }
bool is_set() { return isSet; }
};
class SomeType {};
enum SomeType2 { none, a, b};
class MyObject
{
public:
Property<SomeType*> x;
Property<SomeType2> y;
//This should be generated. //Consider generating ((T)x)->checkMembers() when type is a pointer
bool checkMembers() { return x.is_set() && y.is_set(); }
};
int main(int argc, char * argv[])
{
MyObject* p = new MyObject();
p->x = new SomeType;
cout << p->checkMembers() << endl; // false
p->y = a;
cout << p->checkMembers() << endl; // true
delete p->x;
delete p;
}