I've been wondering how to pass argument to a singleton contructor. I already know how to do a singleton, but I've been unlucky to find a way to do it.
Here is my code (part of it).
Questionnary* Questionnary::getInstance(){
static Questionnary *questionnary = NULL;
if(questionnary == NULL){
cout << "Object created";
questionnary = new Questionnary();
}
else if(questionnary != NULL){
cout << "Object exist";
}
return questionnary;
}
Questionnary::Questionnary(){
cout << "I am an object";
}
//This is want i want to acheive
Questionnary::Questionnary(string name){
cout << "My name is << name;
}
Many thanks in advance
(BTW i know how and why a singleton is bad)
Let me extend Martin York's answer for your use case. I recommend using pointer for argument(s) in this particular situation, as we make use of its inherent property, that it can be "empty".
class Questionnary
{
std::string _str;
static Questionnary& getInstanceImpl(std::string* const s = nullptr)
{
static Questionnary instance{ s };
return instance;
}
Questionnary(std::string* const s)
: _str{ s ? move(*s) : std::string{} } // employ move ctor
{
if (nullptr == s)
throw std::runtime_error{ "Questionnary not initialized" };
}
public:
static Questionnary& getInstance()
{
return getInstanceImpl();
}
static void init(std::string s) // enable moving in
{
getInstanceImpl(&s);
}
Questionnary(Questionnary const&) = delete;
void operator=(Questionnary const&) = delete;
};
I find this approach less confusing, as it let's you get the instance after first initialization without (anyway discarded) arguments:
// first init
Questionnary::init("my single Questionnary");
// later on ...
Questionnary& q = Questionnary::getInstance();
Edit: Removed argument from getInstance function and a few optimizations.
You don't need to allocate the instance of singleton dynamically. It could look the following way (this is sometimes called "lazy loading singleton" ~ the instance is created late & kinda "automatically"):
#include <iostream>
#include <string>
class Questionnary
{
private:
// constructor taking string:
Questionnary(const std::string& name) : name_(name) { }
public:
static Questionnary& getInstance(const std::string& name)
{
static Questionnary q(name);
std::cout << "My name is: " << q.name_ << std::endl;
return q;
}
private:
std::string name_;
};
int main() {
Questionnary::getInstance("Josh");
Questionnary::getInstance("Harry");
}
output:
My name is: Josh
My name is: Josh
Note that constructor will be called only once right when the getInstance is called for the first time.
Have a method to create the instance to pass arguments to the constructor and you could assert in the getInstance() method if CreateInstance has not been called prior to calling it. Like:
class Questionnary
{
private:
// constructor taking string:
Questionnary(const std::string& name) : name_(name)
{
std::cout << "My name is: " << q.name_ << std::endl;
}
static Questionnary* m_instance;
public:
static void createInstance(const std::string& name)
{
assert(!m_instance);
m_instance = new Questionary(name);
}
static void destroyInstance()
{
assert(m_instance);
delete m_instance;
}
static Questionnary* Questionnary::getInstance()
{
assert(m_instance);
return m_instance;
}
private:
std::string name_;
};
//! #file singleton.h
//!
//! #brief Variadic template to make a singleton out of an ordinary type.
//!
//! This template makes a singleton out of a type without a default
//! constructor.
#ifndef SINGLETON_H
#define SINGLETON_H
#include <stdexcept>
template <typename C, typename ...Args>
class singleton
{
private:
singleton() = default;
static C* m_instance;
public:
singleton(const singleton&) = delete;
singleton& operator=(const singleton&) = delete;
singleton(singleton&&) = delete;
singleton& operator=(singleton&&) = delete;
~singleton()
{
delete m_instance;
m_instance = nullptr;
}
static C& create(Args...args)
{
if (m_instance != nullptr)
{
delete m_instance;
m_instance = nullptr;
}
m_instance = new C(args...);
return *m_instance;
}
static C& instance()
{
if (m_instance == nullptr)
throw std::logic_error(
"singleton<>::create(...) must precede singleton<>::instance()");
return *m_instance;
}
};
template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;
#endif // SINGLETON_H
and:
void
singleton_utest::test()
{
try
{
singleton<int, int>::instance();
UTEST_CHECK(false);
}
catch (std::logic_error& e)
{
UTEST_CHECK(true);
}
try
{
UTEST_CHECK((singleton<int, int>::create(1) == 1));
UTEST_CHECK((singleton<int, int>::instance() == 1));
}
catch (...)
{
UTEST_CHECK(false);
}
using stester0 = singleton<tester0>;
try
{
stester0::instance();
UTEST_CHECK(false);
}
catch (std::logic_error& e)
{
UTEST_CHECK(true);
}
try
{
UTEST_CHECK((stester0::create().result() == 0));
UTEST_CHECK((stester0::instance().result() == 0));
}
catch (...)
{
UTEST_CHECK(false);
}
using stester1 = singleton<tester1, int>;
try
{
stester1::instance();
UTEST_CHECK(false);
}
catch (std::logic_error& e)
{
UTEST_CHECK(true);
}
try
{
UTEST_CHECK((stester1::create(1).result() == 1));
UTEST_CHECK((stester1::instance().result() == 1));
}
catch (...)
{
UTEST_CHECK(false);
}
using stester2 = singleton<tester2, int, int>;
try
{
stester2::instance();
UTEST_CHECK(false);
}
catch (std::logic_error& e)
{
UTEST_CHECK(true);
}
try
{
UTEST_CHECK((stester2::create(1, 2).result() == 3));
UTEST_CHECK((stester2::instance().result() == 3));
}
catch (...)
{
UTEST_CHECK(false);
}
}
My version using Modern C++ that wraps an existing type:
#ifndef SINGLETON_H
#define SINGLETON_H
template <typename C, typename ...Args>
class singleton
{
private:
singleton() = default;
static C* m_instance;
public:
~singleton()
{
delete m_instance;
m_instance = nullptr;
}
static C& instance(Args...args)
{
if (m_instance == nullptr)
m_instance = new C(args...);
return *m_instance;
}
};
template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;
#endif // SINGLETON_H
Here is what in looks like in a unit test:
int &i = singleton<int, int>::instance(1);
UTEST_CHECK(i == 1);
tester1& t1 = singleton<tester1, int>::instance(1);
UTEST_CHECK(t1.result() == 1);
tester2& t2 = singleton<tester2, int, int>::instance(1, 2);
UTEST_CHECK(t2.result() == 3);
The problem with this is that instance() requires arguments on each call but only uses them on the first (as noted above). Default arguments cannot be used generally. It may be better to use a create(Args...) method which must precede the call of instance() or throw an exception.
Related
I am trying to implement the functionality of namespaces. The main class Project contains a vector std::vector std::shared_ptr<Class>classes_{}; Each class, respectively, contains similar vectors with Variable and Function. Also, the Class class can have a base class - Class* parent_. The task is such, for example, when adding a new variable (in Class std::vector std::shared_ptr<Variable> vars_{};) or renaming an existing one, it was checked (taking into account visibility) that a variable with such a name does not exist in this class and all his ancestors. The names of the created functions and classes were also checked, etc.
Below is my implementation that I don't like.
Variable::parent_ can be both a class and a function. It is logical to assume that Class, if it does not have a parent class, parent_ was not nullptr, but Project*. In principle, this can be solved by having all classes store Nameable* parent_ rather than a concrete class. But then every time you access parent_ you would have to downcast the pointer.
Traversing all Nameable objects creates a set of temporary vectors (in Nameable::nameables() and in Nameable::get_nameables()).
Please advise how to solve these problems. Or perhaps where you can peep a more beautiful implementation
#include "string"
#include "string_view"
#include "vector"
#include <iostream>
#include <memory>
class Nameable
{
std::string name_{};
//VISIBILITY visibility_{ VISIBILITY::PUBLIC };
protected:
virtual Nameable* parent() const = 0;
virtual std::vector<std::shared_ptr<Nameable>> nameables() const = 0;
void get_nameables(std::vector<std::shared_ptr<Nameable>>& n)
{
std::vector<std::shared_ptr<Nameable>> names = nameables();
if (parent())
parent()->get_nameables(names);
n.insert(n.end(), names.begin(), names.end());
}
public:
Nameable(std::string_view name) : name_(name)
{
//if (!check_name(name)) throw InvalidNameException(name);
}
virtual ~Nameable() {};
std::shared_ptr<Nameable> check_name(std::string_view name) const
{
return std::shared_ptr<Nameable>();
}
const std::string& get_name() const& { return name_; }
void set_name(std::string_view name) { name_ = name; }
};
class Variable;
class Function;
class Class final : public Nameable
{
std::vector<std::shared_ptr<Variable>> vars_{};
std::vector<std::shared_ptr<Function>> funs_{};
Class* parent_{};
Nameable* parent() const override
{
return parent_;
}
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
n.insert(n.end(), vars_.begin(), vars_.end());
n.insert(n.end(), funs_.begin(), funs_.end());
return n;
}
public:
Class(std::string_view name, Class* parent = nullptr)
: Nameable(name), parent_(parent)
{}
std::shared_ptr<Variable> create_var(std::string_view name)
{
vars_.push_back(std::make_shared<Variable>(name, this));
return vars_.back();
}
std::shared_ptr<Function> create_fun(std::string_view name)
{
funs_.push_back(std::make_shared<Function>(name, this));
return funs_.back();
}
};
class Variable final : public Nameable
{
Class* parent_{};
Nameable* parent() const override
{
return parent_;
}
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
return n; // return empty vector
}
public:
Variable(std::string_view name, Class* parent)
: Nameable(name), parent_(parent) {}
};
class Function final : public Nameable
{
Class* parent_{};
std::vector<std::shared_ptr<Variable>> local_vars_{};
Nameable* parent() const override
{
return parent_;
}
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
n.insert(n.end(), local_vars_.begin(), local_vars_.end());
return n;
}
public:
Function(std::string_view name, Class* parent)
: Nameable(name), parent_(parent) {}
};
class Project final : public Nameable
{
std::vector<std::shared_ptr<Class>> classes_{};
Nameable* parent() const override { return nullptr; }
std::vector<std::shared_ptr<Nameable>> nameables() const override
{
std::vector<std::shared_ptr<Nameable>> n{};
n.insert(n.end(), classes_.begin(), classes_.end());
return n;
}
public:
Project(std::string_view name) : Nameable(name){}
};
I'm not sure if I understand your intent clearly, yet maybe use composition instead? It's just easier to maintain. It'd be easier for me if you have provided any use case, but nonetheless I have something like below for you.
// You may want use it in a bitfield mask manner.
enum class NameType : int8_t {
Function = 1,
Variable = 2,
Object = 4,
None = 8
};
// Just simple storage, defaulted if constructed with a default constructor.
struct Nameable {
// union := variable | static_function
using Parent = std::variant<std::optional<std::any>, std::function<std::any(std::any)>>;
explicit Nameable(std::string_view sv, NameType t, const Parent& p = std::nullopt): name(sv), type(t), parent(p)
{
}
std::string name{};
NameType type = NameType::None;
Parent parent = std::nullopt;
};
// Flat aggregator of names (no hierarchy mapping), one-for-all (e.g. per class, per namespace).
struct Collector {
using Nameables = std::vector<std::optional<Nameable>>;
explicit Collector(std::string_view sv, NameType t, const std::optional<std::any>& p = std::nullopt)
{
attach(sv, t, p);
}
void attach(std::string_view sv, NameType t, const std::optional<std::any>& p = std::nullopt)
{
auto n = Nameable(sv, t, p);
names.emplace_back(std::move(n));
}
// combine collectors, such that (f+g)(n) := f(n) + g(n), e.g. for namespace, module, translation unit.
[[maybe_unused]] void attach(const Collector& c)
{
for (const auto& name: c.names) {
attach(name->name, name->type, name->parent);
}
}
bool isUniqueName(std::string_view key) const
{
return std::ranges::all_of(names, [key](const auto& name) {
if (name.has_value() && name.value().name == key) return false;
return true;
});
}
bool isUniqueObjectName(std::string_view key) const
{
return std::ranges::all_of(names, [key](const auto& name) {
if (name.has_value() && name.value().type == NameType::Object && name.value().name == key) return false;
return true;
});
}
std::size_t index(std::string_view key) const
{
for (std::size_t i = 0; i != names.size(); ++i) {
const auto& name = names[i];
if (name.has_value() && name.value().name == key) return i;
}
return std::string::npos;
}
void rename(std::string_view from, std::string_view to)
{
names.at(index(from)).value().name = std::string(to);
}
const Nameable& get(std::string_view key) const
{
if (!names.at(index(key)).has_value()) throw std::bad_optional_access();
return names.at(index(key)).value();
}
std::any variable(std::string_view name) const
{
const auto& nameable = get(name);
if (const auto& var = nameable.parent; std::holds_alternative<std::optional<std::any>>(var)) {
if (const auto& opt = std::get<0>(var); opt.has_value()) return opt.value();
throw std::bad_optional_access();
}
throw std::bad_variant_access();
}
Nameables names{};
};
The idea is to collect names hierarchically but through "formation". Alternatively, just use trees, or dictionaries (as it has been already stated).
namespace outer {
Collector cOuter;
constexpr int GLOBAL = 1;
namespace inner {
Collector cInner;
void f() {}
namespace internal {
Collector cInternal;
Data d{};
}
}
}
I'm not certain if you're really interested in storing objects, though.
With std::any it may require some gymnastic, but you can handle it.
I would suggest std::optional, but this need trivially copyable structure, so be careful with adding new fields. Collecting member functions require some additional std::function signature. If you need more information, e.g. about types, then store them as type traits, or concepts, or anyhow. Eventually, introduce std::variant<Variable, Function, Class/Object>. Let give them do their job (Variable/+types, Function/+params, Class/+hierarchy) and compose them at the end.
struct SomeClass {
static auto Something(int y = 3) noexcept
{
return 1 + y;
}
int var1 = 0;
float var2 = 5.5;
};
SomeClass s{};
auto c = Collector("SomeClass", NameType::Object, s);
c.attach("var1", NameType::Variable, s.var1);
c.attach("var2", NameType::Variable, s.var2);
c.attach("Something", NameType::Function, SomeClass::Something);
std::cout << c.names[0].value().name << '\n'; // "SomeClass", etc.
std::cout << std::boolalpha << c.isUniqueName("var1") << '\n'; // false
c.rename("var1", "var_1");
std::cout << std::boolalpha << c.isUniqueName("var1") << '\n'; // true
std::cout << std::boolalpha << c.isUniqueObjectName("SomeClass") << '\n'; // false
auto var2 = c.variable("var2");
auto vf = std::any_cast<float>(var2);
std::cout << std::to_string(vf) << '\n'; // 5.500000
I am currently reading the "3D Game Engine Architecture" book by David H. Eberly, and decided to implement my own little reference counting smart pointer. I have mostly followed his implementation, but I am experiencing a problem with my implementation.
I created a function called 'CreateRef' which returns a Pointer. All is well when I use this function in the same scope as the object I have created, but the moment I put the object in the global scope it destroys the object right after creation.
class Object
{
public:
void IncrementReferences()
{
++m_References;
}
void DecrementReferences()
{
if(--m_References == 0) delete this;
}
int GetReferenceCount() const { return m_References; }
private:
int m_References = 0;
};
template<class T>
class Pointer
{
public:
//costr and destr
Pointer(T* pObject = nullptr)
{
m_pObject = pObject;
if (m_pObject)
m_pObject->IncrementReferences();
}
Pointer(const Pointer& rPointer)
{
m_pObject = rPointer.m_pObject;
if (m_pObject)
m_pObject->IncrementReferences();
}
~Pointer()
{
if (m_pObject)
m_pObject->DecrementReferences();
}
// implicit conversions
operator T* () const
{
return m_pObject;
}
T& operator* () const
{
return *m_pObject;
}
T* operator-> () const
{
return m_pObject;
}
// Assignment
Pointer& operator= (T* pObject)
{
if (m_pObject != pObject)
{
if (pObject)
pObject->IncrementReferences();
if (m_pObject)
m_pObject->DecrementReferences();
m_pObject = pObject;
}
return *this;
}
Pointer& operator= (const T* rReference)
{
if (m_pObject != rReference)
{
if (rReference)
rReference->IncrementReferences();
if (m_pObject)
m_pObject->DecrementReferences();
m_pObject = rReference;
}
return *this;
}
// Comparisons
bool operator== (T* pObject) const { return m_pObject == pObject; }
bool operator!= (T* pObject) const { return m_pObject != pObject; }
bool operator== (const Pointer& rReference) const { return m_pObject == rReference.m_pObject; }
bool operator!= (const Pointer& rReference) const { return m_pObject != rReference.m_pObject; }
protected:
// The shared object
T* m_pObject;
};
template<typename T>
using Ref = Pointer<T>;
template<typename T, typename ...Args>
constexpr Ref<T> CreateRef(Args&&... args)
{
return Ref<T>(new T(args...));
}
Main
static Ref<Person> person = nullptr; // Doesn't work like this
static void DoSomething()
{
person = CreateRef<Person>("Name");
std::cout << "References " << person->GetReferenceCount() << std::endl;
Ref<Person> newPerson = person;
std::cout << "References " << newPerson->GetReferenceCount() << std::endl;
}
int main()
{
DoSomething();
std::cout << person->GetReferenceCount();
}
I have a feeling I am doing something wrong with the 'Pointer' class but I can't quite understand what I am missing.
Thanks for the help. I found two solutions to my problem.
First solution is to add a copy assignment operator to the Pointer class.
Pointer& operator= (Pointer& rPointer)
{
if (m_pObject != rPointer.m_pObject)
{
if (rPointer)
rPointer.m_pObject->IncrementReferences();
if (m_pObject)
m_pObject->DecrementReferences();
m_pObject = rPointer.m_pObject;
}
return *this;
}
Another solution (albeit not what I was looking for) was to change the return type of the CreateRef() function to be a T*
template<typename T, typename ...Args>
constexpr T* CreateRef(Args&&... args)
{
return new T(args...);
}
I modified the factory pattern with self registering types from this blog post for my own needs. Instead of strings I use UUIDs (using boost.uuid) to register & build my node sub-classes.
The factory and corresponding node and node_* subclasses are part of a library. I link against that library (static library) in my client application and then want to use the library's factory::build() function to build objects based on the known UUIDs.
The problem I am facing is that everything is working well both as a standalone minimal example (see below) and within my library itself. However, when I use the factory::build() function provided by the library in my application I notice that the factory::m_generators map is empty and therefore the factory doesn't know how to build any objects.
When I manually create a dummy object first the factory is able to build further instances of the same class. This indicates that the node sub-classes never get instantiated and therefore also never get a chance to register themselves at the factory.
How can I solve this problem?
Here's my code (live example):
#include <iostream>
#include <unordered_map>
#include <functional>
#include <memory>
#include <boost/functional/hash.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/string_generator.hpp>
class node;
/**
* #brief The factory class to build #p node items.
*/
class factory
{
public:
using key_type = boost::uuids::uuid;
using key_hash = boost::hash<key_type>;
using generator = std::function<std::unique_ptr<node>()>;
template<typename Derived>
struct registrar
{
registrar(const key_type& key)
{
factory::instance().register_generator(key, [](){
return std::make_unique<Derived>();
});
}
registrar(const std::string& uuid_string)
{
try {
boost::uuids::string_generator gen;
registrar(gen(uuid_string));
} catch (...) {
;
}
}
};
static factory& instance() noexcept
{
static factory f;
return f;
}
bool register_generator(const key_type& key, generator&& generator)
{
auto [it, emplaced] = m_generators.try_emplace(key, std::move(generator));
return emplaced;
}
[[nodiscard]] std::unique_ptr<node> build(const key_type& key) const
{
if (const auto& it = m_generators.find(key); it not_eq m_generators.cend())
return it->second();
return nullptr;
}
[[nodiscard]] std::unique_ptr<node> build(const char* uuid_string) const noexcept
{
try {
boost::uuids::string_generator gen;
return build(gen(uuid_string));
} catch (...) {
return nullptr;
}
}
private:
std::unordered_map<key_type, generator, key_hash> m_generators;
factory() = default;
factory(const factory& other) = default;
factory(factory&& other) = default;
virtual ~factory() = default;
};
/**
* #brief The node base class.
*/
struct node
{
node(const std::string& uuid_string) :
m_uuid_string(uuid_string)
{
}
[[nodiscard]] const std::string& uuid_string() const noexcept {
return m_uuid_string;
}
private:
std::string m_uuid_string;
};
/**
* #brief A template for #p node subclasses.
*/
template <class derived>
struct node_template :
node,
factory::registrar<derived>
{
node_template(const std::string& uuid_string) :
node(uuid_string),
factory::registrar<derived>(uuid_string)
{
(void) registered;
}
static bool do_register() {
std::cout << "node_template::do_register()" << std::endl;
derived d; // I am not sure if one should in some way force this to not be optimized away.
return true;
}
inline static bool registered = do_register();
};
struct A : node_template<A> {
A() : node_template("63cb8eeb-b90b-46c7-aaa8-3a349fcba3c5") { }
};
struct B : node_template<B> {
B() : node_template("1f24abfc-936f-4524-ae3b-cc346335ecbb") { }
};
static void build_and_print(const std::string& uuid_string)
{
if (auto node = factory::instance().build(uuid_string.c_str()); node)
std::cout << "node.uuid_string() = " << node->uuid_string() << std::endl;
else
std::cout << "Cannot build node object: Unknown UUID." << std::endl;
}
int main(void)
{
////////////////////////////////////////////////////////////////////////////////////////////////////
/// PROBLEM: If I do not construct these objects, they never register themselves at the factory. ///
////////////////////////////////////////////////////////////////////////////////////////////////////
#if 0
A a;
B b;
#endif
// A
build_and_print("63cb8eeb-b90b-46c7-aaa8-3a349fcba3c5");
// B
build_and_print("1f24abfc-936f-4524-ae3b-cc346335ecbb");
// Unknown UUID
build_and_print("9b20cc29-c7ca-4796-acb2-6ca6b80fa934");
return 0;
}
This previous question of mine is related.
I realize that I'll most likely get a lot of "you shouldn't do that because..." answers and they are most welcome and I'll probably totally agree with your reasoning, but I'm curious as to whether this is possible (as I envision it).
Is it possible to define a type of dynamic/generic object in C++ where I can dynamically create properties that are stored and retrieved in a key/value type of system? Example:
MyType myObject;
std::string myStr("string1");
myObject.somethingIJustMadeUp = myStr;
Note that obviously, somethingIJustMadeUp is not actually a defined member of MyType but it would be defined dynamically. Then later I could do something like:
if(myObject.somethingIJustMadeUp != NULL);
or
if(myObject["somethingIJustMadeUp"]);
Believe me, I realize just how terrible this is, but I'm still curious as to whether it's possible and if it can be done in a way that minimizes it's terrible-ness.
C++Script is what you want!
Example:
#include <cppscript>
var script_main(var args)
{
var x = object();
x["abc"] = 10;
writeln(x["abc"]);
return 0;
}
and it's a valid C++.
You can do something very similar with std::map:
std::map<std::string, std::string> myObject;
myObject["somethingIJustMadeUp"] = myStr;
Now if you want generic value types, then you can use boost::any as:
std::map<std::string, boost::any> myObject;
myObject["somethingIJustMadeUp"] = myStr;
And you can also check if a value exists or not:
if(myObject.find ("somethingIJustMadeUp") != myObject.end())
std::cout << "Exists" << std::endl;
If you use boost::any, then you can know the actual type of value it holds, by calling .type() as:
if (myObject.find("Xyz") != myObject.end())
{
if(myObject["Xyz"].type() == typeid(std::string))
{
std::string value = boost::any_cast<std::string>(myObject["Xyz"]);
std::cout <<"Stored value is string = " << value << std::endl;
}
}
This also shows how you can use boost::any_cast to get the value stored in object of boost::any type.
This can be a solution, using RTTI polymorphism
#include <map>
#include <memory>
#include <iostream>
#include <stdexcept>
namespace dynamic
{
template<class T, class E>
T& enforce(T& z, const E& e)
{ if(!z) throw e; return z; }
template<class T, class E>
const T& enforce(const T& z, const E& e)
{ if(!z) throw e; return z; }
template<class Derived>
class interface;
class aggregate;
//polymorphic uncopyable unmovable
class property
{
public:
property() :pagg() {}
property(const property&) =delete;
property& operator=(const property&) =delete;
virtual ~property() {} //just make it polymorphic
template<class Interface>
operator Interface*() const
{
if(!pagg) return 0;
return *pagg; //let the aggregate do the magic!
}
aggregate* get_aggregate() const { return pagg; }
private:
template<class Derived>
friend class interface;
friend class aggregate;
static unsigned gen_id()
{
static unsigned x=0;
return enforce(++x,std::overflow_error("too many ids"));
}
template<class T>
static unsigned id_of()
{ static unsigned z = gen_id(); return z; }
aggregate* pagg;
};
template<class Derived>
class interface: public property
{
public:
interface() {}
virtual ~interface() {}
unsigned id() const { return property::id_of<Derived>(); }
};
//sealed movable
class aggregate
{
public:
aggregate() {}
aggregate(const aggregate&) = delete;
aggregate& operator=(const aggregate&) = delete;
aggregate(aggregate&& s) :m(std::move(s.m)) {}
aggregate& operator=(aggregate&& s)
{ if(this!=&s) { m.clear(); std::swap(m, s.m); } return *this; }
template<class Interface>
aggregate& add_interface(interface<Interface>* pi)
{
m[pi->id()] = std::unique_ptr<property>(pi);
static_cast<property*>(pi)->pagg = this;
return *this;
}
template<class Inteface>
aggregate& remove_interface()
{ m.erase[property::id_of<Inteface>()]; return *this; }
void clear() { m.clear(); }
bool empty() const { return m.empty(); }
explicit operator bool() const { return empty(); }
template<class Interface>
operator Interface*() const
{
auto i = m.find(property::id_of<Interface>());
if(i==m.end()) return nullptr;
return dynamic_cast<Interface*>(i->second.get());
}
template<class Interface>
friend aggregate& operator<<(aggregate& s, interface<Interface>* pi)
{ return s.add_interface(pi); }
private:
typedef std::map<unsigned, std::unique_ptr<property> > map_t;
map_t m;
};
}
/// this is a sample on how it can workout
class interface_A: public dynamic::interface<interface_A>
{
public:
virtual void methodA1() =0;
virtual void methodA2() =0;
};
class impl_A1: public interface_A
{
public:
impl_A1() { std::cout<<"creating impl_A1["<<this<<"]"<<std::endl; }
virtual ~impl_A1() { std::cout<<"deleting impl_A1["<<this<<"]"<<std::endl; }
virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_A2: public interface_A
{
public:
impl_A2() { std::cout<<"creating impl_A2["<<this<<"]"<<std::endl; }
virtual ~impl_A2() { std::cout<<"deleting impl_A2["<<this<<"]"<<std::endl; }
virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
};
class interface_B: public dynamic::interface<interface_B>
{
public:
virtual void methodB1() =0;
virtual void methodB2() =0;
};
class impl_B1: public interface_B
{
public:
impl_B1() { std::cout<<"creating impl_B1["<<this<<"]"<<std::endl; }
virtual ~impl_B1() { std::cout<<"deleting impl_B1["<<this<<"]"<<std::endl; }
virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_B2: public interface_B
{
public:
impl_B2() { std::cout<<"creating impl_B2["<<this<<"]"<<std::endl; }
virtual ~impl_B2() { std::cout<<"deleting impl_B2["<<this<<"]"<<std::endl; }
virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
};
int main()
{
dynamic::aggregate agg1;
agg1 << new impl_A1 << new impl_B1;
dynamic::aggregate agg2;
agg2 << new impl_A2 << new impl_B2;
interface_A* pa = 0;
interface_B* pb = 0;
pa = agg1; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
agg2 = std::move(agg1);
pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
return 0;
}
tested with MINGW4.6 on WinXPsp3
Yes it is terrible. :D
It had been done numerous times to different extents and success levels.
QT has Qobject from which everything related to them decends.
MFC has CObject from which eveything decends as does C++.net
I don't know if there is a way to make it less bad, I guess if you avoid multiple inheritance like the plague (which is otherwise a useful language feature) and reimplement the stdlib it would be better. But really if that is what you are after you are probably using the wrong language for the task.
Java and C# are much better suited to this style of programming.
#note if I have read your question wrong just delete this answer.
Check out Dynamic C++
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;
}