Related
I have a simple object cache:
class ObjectCache
{
public:
ObjectCache() {}
const Object& object(const std::string &key) const
{
auto it = cache_.find(key);
if (it != cache_.end())
{
return it->second;
}
return Object(); // const-ref to temporary
}
void insert(const std::string &key, const Object &object)
{
cache_[key] = object;
}
private:
std:map<std::string, Object> cache_;
};
The return type is when retrieving from the cache is a const ref.
However, in the case the key is not found, a const ref to a temporary is returned and results in undefined behaviour for calling code.
How can I address the issue of returning a const ref to a temporary?
Some thoughts I've had:
Insert and return pointers (cache takes ownership), nullptr means not found
Provide ObjectCache::contains so calling code can check before accessing
Maintain either a static or empty Object member and return a reference to that when not found
An ideal solution is to maintain the current cache but return a pointer to a reference:
class ObjectCache
{
public:
ObjectCache() {}
const Object* object(const std::string &key) const
{
auto it = cache_.find(key);
if (it != cache_.end())
{
return &(it->second);
}
return nullptr;
}
void insert(const std::string &key, const Object &object)
{
cache_[key] = object;
}
private:
std:map<std::string, Object> cache_;
};
This has the added benefit of avoiding creating objects on the heap and memory management but allows calling code to work with a nullptr as not found.
You could offer an interface that allows the caller express the desired behaviour:
#include <map>
#include <string>
#include <stdexcept>
#include <boost/optional.hpp>
struct Object {};
struct NoObject : std::logic_error
{
using std::logic_error::logic_error;
};
class ObjectCache
{
public:
ObjectCache() {}
/// Require an object for the corresponding key
/// #param key
/// #exception NoObject if the key does not represent an object
/// in cache
const Object& require(const std::string &key) const
{
auto it = cache_.find(key);
if (it != cache_.end())
{
return it->second;
}
throw NoObject(key);
}
/// return the object corresponding to key if it exists
/// If not, call the factory function, store the result and return
/// the corresponding object
template<class Factory>
const Object& acquire(const std::string &key, Factory&& factory)
{
auto it = cache_.find(key);
if (it == cache_.end())
{
it = cache_.emplace(key, factory(key)).first;
}
return it->second;
}
/// Return the object corresponding to key if it exists.
boost::optional<const Object&> query(const std::string &key) const
{
auto it = cache_.find(key);
if (it != cache_.end())
{
return it->second;
}
else
{
return {};
}
}
void insert(const std::string &key, const Object &object)
{
cache_[key] = object;
}
private:
std::map<std::string, Object> cache_;
};
int main()
{
ObjectCache cache;
// fetch existing or create
auto& x = cache.acquire("foo", [](std::string const& key){
return Object();
});
// fetch existing or exception
auto& y = cache.require("foo");
// fetch existing if exists
if(auto z = cache.query("foo"))
{
auto&& zz = z.get();
}
}
In C# / .NET you can do something like this:
someThing.text = "blah";
String blah = someThing.text;
However, the above code does not actually interact with the someThing's text String directly, it uses a get and set property. Similarly, read-only properties can be used.
Is there a way to do something similar in native C++? (not C++ .NET)
WARNING: This is a tongue-in-cheek response and is terrible!!!
Yes, it's sort of possible :)
template<typename T>
class Property
{
private:
T& _value;
public:
Property(T& value) : _value(value)
{
} // eo ctor
Property<T>& operator = (const T& val)
{
_value = val;
return *this;
}; // eo operator =
operator const T&() const
{
return _value;
}; // eo operator ()
};
Then declare your class, declaring properties for your members:
class Test
{
private:
std::string _label;
int _width;
public:
Test() : Label(_label)
, Width(_width)
{
};
Property<std::string> Label;
Property<int> Width;
};
And call C# style!
Test a;
a.Label = "blah";
a.Width = 5;
std::string label = a.Label;
int width = a.Width;
In .NET properties are syntactic sugar for the real get and set functions which are emitted behind the scenes (in fact they are more than syntactic sugar because properties are emitted in the resulting IL and could be used with Reflection). So in C++ you would need to explicitly write those functions as there's no such notion as property.
I warn you, it is not fully compatible native C++: Microsoft-specific C++ only.
The Microsoft compiler allows you to use declspec(property), this way:
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
// here you define the property and the functions to call for it
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5; // THERE YOU GO
return s.the_prop;
}
cf Microsoft Documentation for more details: declspec(property).
Moo-Juice's answer looks really cool, but has a drawback: you can't use these properties like normal expressions of type T, as you can in C#.
For instance,
a.text.c_str() won't compile (‘class Property<std::basic_string<char> >’ has no member named ‘c_str’)
std::cout << a.text won't compile either (template argument deduction/substitution failed)
I would suggest the following enhancement to template<typename T> class Property:
T& operator() ()
{
return _value;
}
T const& operator() () const
{
return _value;
}
Then you can access the property's members with (), such as:
char const *p = a.text().c_str();
And you can use the property in expressions where the type must be deduced:
std::cout << a.text();
A property in .NET is associated with a get and/or a set member function, so it's really just syntactic sugar. The closest you can get with C++ is to use overloading to give the getter and setter the same name:
const std::string &test() const { return text_; }
void test(const std::string &value) { text_ = value; }
Obviously, you will still have to provide parenthesis for the call:
someThing.text("blah");
String blah = someThing.text();
Yes but it's vendor specific. Microsoft has declspec(property).
C++Builder's implementation is a bit more advanced (via vendor specific __property keyword) in that you could have indexed accessors (which can be of any types you wish).
Also check this out (without relying on vendor specific keywords): http://www.codeproject.com/KB/cpp/cpp_property_indexer.aspx
#include <iostream>
#include <string>
using namespace std;
// ------------------------------------------------------------------
#define PROPERTY_GET_SET(CLASS, NAME, TYPE) GetSetProperty<CLASS, TYPE> NAME() { return GetSetProperty<CLASS, TYPE>(this, &CLASS::get_##NAME, &CLASS::set_##NAME); }
#define PROPERTY_GET(CLASS, NAME, TYPE) GetProperty<CLASS, TYPE> NAME() { return GetProperty<CLASS, TYPE>(this, &CLASS::get_##NAME); }
#define PROPERTY_SET(CLASS, NAME, TYPE) SetProperty<CLASS, TYPE> NAME() { return SetProperty<CLASS, TYPE>(this, &CLASS::set_##NAME); }
template <typename CLASS, typename TYPE>
struct GetSetProperty {
typedef TYPE (CLASS::*Getter_t)() const;
typedef void (CLASS::*Setter_t)(TYPE);
GetSetProperty(CLASS* instance, Getter_t getter, Setter_t setter) : m_instance(instance), m_getter(getter), m_setter(setter) {}
operator TYPE() const { return (this->m_instance->*this->m_getter)(); }
GetSetProperty<CLASS, TYPE>& operator=(TYPE value) { (this->m_instance->*this->m_setter)(value); return *this; }
CLASS* const m_instance;
const Getter_t m_getter;
const Setter_t m_setter;
};
template <typename CLASS, typename TYPE>
struct GetProperty {
typedef TYPE (CLASS::*Getter_t)() const;
GetProperty(CLASS* instance, Getter_t getter) : m_instance(instance), m_getter(getter) {}
operator TYPE() const { return (this->m_instance->*this->m_getter)(); }
CLASS* const m_instance;
const Getter_t m_getter;
};
template <typename CLASS, typename TYPE>
struct SetProperty {
typedef void (CLASS::*Setter_t)(TYPE);
SetProperty(CLASS* instance, Setter_t setter) : m_instance(instance), m_setter(setter) {}
SetProperty<CLASS, TYPE>& operator=(TYPE value) { (this->m_instance->*this->m_setter)(value); return *this; }
CLASS* const m_instance;
const Setter_t m_setter;
};
template <typename CLASS, typename TYPE>
ostream& operator<<(ostream& ostr, const GetSetProperty<CLASS, TYPE>& p) { ostr << (p.m_instance->*p.m_getter)(); return ostr; }
template <typename CLASS, typename TYPE>
ostream& operator<<(ostream& ostr, const GetProperty<CLASS, TYPE>& p) { ostr << (p.m_instance->*p.m_getter)(); return ostr; }
// ------------------------------------------------------------------
class Dummy
{
public:
Dummy() : m_value1(42) {}
PROPERTY_GET_SET(Dummy, Value1, int);
PROPERTY_GET_SET(Dummy, Value2, const string&);
protected:
virtual int get_Value1() const { return this->m_value1; }
virtual void set_Value1(int value) { this->m_value1 = value; }
virtual const string& get_Value2() const { return this->m_value2; }
virtual void set_Value2(const string& value) { this->m_value2 = value; }
private:
int m_value1;
string m_value2;
};
int main(int argc, char* argv[]) {
Dummy d;
cout << d.Value1() << endl;
d.Value1() = 3;
cout << d.Value1() << endl;
cout << d.Value2() << endl;
d.Value2() = "test";
cout << d.Value2() << endl;
return 0;
}
// ------------------------------------------------------------------
By using std::function you can get pretty close. Featurewise everything is here.
First create the templated Property class:
#include <functional>
template<class T>
class Property
{
std::function<T (void)> _get;
std::function<void(const T&)> _set;
public:
Property(
std::function<T (void)> get,
std::function<void(const T&)> set)
: _get(get),
_set(set)
{ }
Property(
std::function<T(void)> get)
: _get(get),
_set([](const unsigned int&){})
{ }
operator T () const { return _get(); }
void operator = (const T& t) { _set(t); }
};
Use the Property in a class by creating a get and a set method similar to what you would in do C#:
class Test
{
private:
std::string _label;
public:
Property<std::string> Label = Property<std::string>
(
[this]()->std::string
{
return this->_label;
},
[this](const std::string& value)
{
this->_label = value;
}
);
Property<unsigned int> LabelSize = Property<unsigned int>
(
[this]()->unsigned int
{
return this->_label.size();
}
);
};
Testing this code:
Test test;
test.Label = "std functional";
std::cout << "label = " << std::string(test.Label) << std::endl
<< "label size = " << int(test.LabelSize) << std::endl;
will output
label = std functional
label size = 14
I think this is as syntactic-sugar-coated as you can get it in c++ :)
Probably the best option currently is to use the microsoft's __declspec( property( get=get_func_name, put=put_func_name ) ) PropertyType PropertyName attribute.
it is also supported by clang,
it is converted into your getter/setter when compiled (won't add any new variables),
in use, it is the closest thing to a real property (can access property of a property...).
But if you're using other compilers, you could use macros:
#define PROPERTY_GEN(Class, Type, Name, GetMethod, SetMethod) \
class Property_##Name { \
public: \
Property_##Name(Class* parent) : _parent(parent) { } \
Type operator = (Type value) \
{ \
_parent->SetMethod(value); \
return _parent->GetMethod(); \
} \
operator Type() const \
{ \
return static_cast<const Class*>(_parent)->GetMethod(); \
} \
Property_##Name& operator =(const Property_##Name& other) \
{ \
operator=(other._parent->GetMethod()); return *this; \
}; \
Property_##Name(const Property_##Name& other) = delete; \
private: \
Class* _parent; \
} Name { this };
// PROPERTY - Declares a property with the default getter/setter method names.
#define PROPERTY(Class, Type, Name) \
PROPERTY_GEN(Class, Type, Name, get_##Name, set_##Name)
Then use them like:
class SomeClass
{
public:
PROPERTY(SomeClass, int, Value)
int get_Value() const { return _value; }
void set_Value(int value) { _value = value; }
private:
int _value = 0;
};
int main()
{
SomeClass s, c;
s.Value = 5;
c.Value = 3 * s.Value;
s.Value = c.Value;
}
You could also add other macro variants for read-only, write-only properties and read-only non-const getters. To be able to access sub-properties via ->, you could add operator-> overloads to the macro.
Compared to microsoft's __declspec(property(...)), getter and setter methods can be made private but this isn't a real advantage since client might need to take the address of a getter/setter sometimes.
There is also a disadvantage of having an additional _parent variable for every property, and you would need to explicitly define copy constructors for parent classes if they are used.
I realize it's this question is probably too old to add another answer but to expand on Moo-Juice's answer, I've come up with a pretty neat and simple solution:
/// Utility for functions get, set & ptr.
template<typename TVal>
using GetFn = std::function<const TVal& (void)>;
template<typename TVal>
using SetFn = std::function<void(const TVal&)>;
template<typename TVal>
using PtrFn = std::function<TVal* (void)>;
/// The property class and each specialization utility.
template<typename TVal, bool Delegate, bool ReadOnly>
class Property;
template<typename TVal>
using PropertyGetSet = Property<TVal, false, false>;
template<typename TVal>
using PropertyDelGetSet = Property<TVal, true, false>;
template<typename TVal>
using PropertyGet = Property<TVal, false, true>;
template<typename TVal>
using PropertyDelGet = Property<TVal, true, true>;
/// <summary>
/// Property get-set.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, false, false>
{
public:
typedef TVal Value;
Property(const TVal& val)
: m_value(val)
{}
inline const TVal& Get() const { return m_value; }
inline void Set(const TVal& val) { m_value = val; }
inline TVal* Ptr() { return &m_value; }
private:
TVal m_value;
};
/// <summary>
/// Property delegate get-set.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, true, false>
{
public:
typedef TVal Value;
Property(GetFn<TVal> getFn, SetFn<TVal> setFn, PtrFn<TVal> ptrFn)
: m_getFn(getFn)
, m_setFn(setFn)
, m_ptrFn(ptrFn)
{}
inline const TVal& Get() const { return m_getFn(); }
inline void Set(const TVal& val) { m_setFn(val); }
inline TVal* Ptr() { return m_ptrFn(); }
private:
GetFn<TVal> m_getFn;
SetFn<TVal> m_setFn;
PtrFn<TVal> m_ptrFn;
};
/// <summary>
/// Property get.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, false, true>
{
public:
typedef TVal Value;
Property(const TVal& val)
: m_value(val)
{}
inline const TVal& Get() const { return m_value; }
inline TVal* Ptr() { return &m_value; }
private:
TVal m_value;
};
/// <summary>
/// Property delegate get.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, true, true>
{
public:
typedef TVal Value;
Property(GetFn<TVal> getFn, PtrFn<TVal> ptrFn)
: m_getFn(getFn)
, m_ptrFn(ptrFn)
{}
inline const TVal& Get() const { return m_getFn(); }
inline TVal* Ptr() { return m_ptrFn(); }
private:
GetFn<TVal> m_getFn;
PtrFn<TVal> m_ptrFn;
};
And then to use it:
PropertyGetSet<std::string> strGetSet = PropertyGetSet<std::string>("GetSet");
std::string m_strGetSet = "DelGetSet";
PropertyDelGetSet<std::string> strDelGetSet =
PropertyDelGetSet<std::string>(
[&]() -> const std::string& { return m_strGetSet; },
[&](const std::string& val) { m_strGetSet = val; },
[&]() { return &m_strGetSet; /* throw? */ });
// The get (read-only) version is the same but without the set function
Some caveats:
The get function returns a const& so you are not able to use it for changing the value, this is by design as it would allow people to use the reference to set the value instead of the explicit Set which gives the advantage of knowing when the value is set.
There is no syntactic sugar for the get-set-ptr functions, personally, I didn't like using operators cause it made the underlying system more obtuse, so using explicit functions lets the user know that it's a property and not something else. But if you may, you could sprinkle some operator overloads.
All specializations have a Ptr function which will be the pointer of the data. However, when using the delegate version, you can choose to throw so anyone trying to use it will have to work around it. The reason it's there is that in the worst-case scenario you may try to use the pointer for a very particular situation, I would highly advise not to use this tho, so feel free to remove it or make an extra specialization for it.
Lastly, it's a bit verbose, you could wrap the usage in a macro to make the syntax a bit shorter, but personally, I like it the way it is as it's more explicit that way.
EDIT:
You may run into the same issue I had with this design, have a look at the following link for the issue and the solution I've come up with: https://stackoverflow.com/a/68563492/3339838
Another try to enhance Moo-Juice's answer, by defining a Getter class (which the client can only get) and a Getter-Setter class which is also assignable:
template <typename T>
class Getter {
protected:
T &_value;
public:
Getter(T &value) : _value(value) {}
operator const T() const {
return _value;
}
};
template <typename T>
class GetterSetter : public Getter<T> {
using Getter<T>::_value;
using Getter<T>::Getter;
public:
GetterSetter<T> & operator=(const T val) {
_value = val;
return *(this);
}
};
This gives you the option to decide which properties could be changed from outside the class, and which will only change internally.
No, there is not. You would just create getter and setter functions:
someThing.setText("blah");
std::string blah = someThing.getText();
I am implementing an object that makes use of unordered_map. The object is to be generic, so templates everywhere. In particular the operator== and operator() are wrapped into structures that are used by the unordered_map to respectively check if keys are equal and to generate hash values for keys. I'd like the user to write their own functions that implement the above two operators and pass those methods as input to the class object. The structs would then use those objects. I'm having some trouble with scopes and can't seem to figure out how to do it. Here's my code:
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
template <typename O>
class aClass
{
public:
aClass( bool (usrIsEq)(O, O) ,
std::size_t (usrHashFtn)(O) )
{
this->usrIsEq = usrIsEq;
this->usrHashFtn = usrHashFtn;
}
void add(O k, std::string v)
{
iTable[ {k} ] = v;
}
std::string get(O k)
{
return iTable[ {k} ];
}
private:
bool (*usrIsEq)(O, O);
std::size_t (*usrHashFtn)(O);
struct Key
{
O obj;
bool operator==(const Key &other) const
{
std::cout << "obj " << obj << std::endl;
return usrIsEq(obj, other.obj);
}
};
struct KeyHasher
{
std::size_t operator()(const Key &k) const
{
return usrHashFtn(k);
}
};
std::unordered_map<Key, std::string, KeyHasher> iTable;
};
bool isEqInts(int a, int b)
{
return a == b;
}
std::size_t intHashFtn(int x)
{
std::hash<int> hf;
return hf(x);
}
int main()
{
aClass<int> x(isEqInts, intHashFtn);
x.add( 1, std::string("hello") );
}
I'm not entirely sure how to implement the structs Key and KeyHasher so that they use the functions contained inside the class. The only thing I truly care about is that the functions are given as input to the class constructor. Everything else can be scrapped.
The main problem that's tripping you up is that Key has no knowledge usrIsEq and KeyHasher has no knowledge of usrHashFtn. You need to pass a pointer or reference to an object of aClass to those classes.
Here' one suggestion:
struct Key
{
O obj;
aClass* ac;
bool operator==(const Key &other) const
{
std::cout << "obj " << obj << std::endl;
return ac->usrIsEq(obj, other.obj);
}
};
struct KeyHasher
{
std::size_t operator()(const Key &k) const
{
return k.ac->usrHashFtn(k.obj);
}
};
and update the places where you use Key to access the table:
void add(O k, std::string v)
{
iTable[{k, this}] = v;
}
std::string get(O k)
{
return iTable[{k, this}];
}
I am making a class that shares data between several objects using dynamic memory. The relevant parts of the class are shown below.
class StrBlob
{
public:
StrBlob::StrBlob(std::initializer_list<std::string> il) :
data(std::make_shared<std::vector<std::string>>(il)) {}
void push_back(const std::string &t) const { data->push_back(t); }
private:
std::shared_ptr<std::vector<std::string>> dataPtr;
};
I understand that by making push_back a const member function, I am saying that this function will not change the member dataPtr. However, the underlying vector that dataPtr points to is not const, as shown by the below code.
//The result is foo = {"bar", "foobar"}
const StrBlob foo = {"bar"};
foo.push_back("foobar");
Is it possible or even desirable to make the underlying vector const by making the StrBlob object const? Should be something like making dataPtr a pointer to const when the object is const, but I'm not sure how to achieve that.
You can make a thin wrapper around std::shared_ptr (details omitted like ctor etc):
#include <memory>
template< class T > class const_propagated_shared_ptr {
std::shared_ptr<T> m_ptr;
public:
T &operator*() { return m_ptr.operator*(); }
T* operator->() { return m_ptr.operator->(); }
const T &operator*() const { return m_ptr.operator*(); }
const T *operator->() const { return m_ptr.operator->(); }
};
class Foobar {
const_propagated_shared_ptr<int> m_ptr;
public:
void f1() { *m_ptr = 10; }
void f2() const { *m_ptr = 10; } // compile error
};
But as this is implementation detail of the class (Foobar in this case) I am not sure that it worse the effort, as to let modify data by const method or not can be controlled by class designer.
In C# / .NET you can do something like this:
someThing.text = "blah";
String blah = someThing.text;
However, the above code does not actually interact with the someThing's text String directly, it uses a get and set property. Similarly, read-only properties can be used.
Is there a way to do something similar in native C++? (not C++ .NET)
WARNING: This is a tongue-in-cheek response and is terrible!!!
Yes, it's sort of possible :)
template<typename T>
class Property
{
private:
T& _value;
public:
Property(T& value) : _value(value)
{
} // eo ctor
Property<T>& operator = (const T& val)
{
_value = val;
return *this;
}; // eo operator =
operator const T&() const
{
return _value;
}; // eo operator ()
};
Then declare your class, declaring properties for your members:
class Test
{
private:
std::string _label;
int _width;
public:
Test() : Label(_label)
, Width(_width)
{
};
Property<std::string> Label;
Property<int> Width;
};
And call C# style!
Test a;
a.Label = "blah";
a.Width = 5;
std::string label = a.Label;
int width = a.Width;
In .NET properties are syntactic sugar for the real get and set functions which are emitted behind the scenes (in fact they are more than syntactic sugar because properties are emitted in the resulting IL and could be used with Reflection). So in C++ you would need to explicitly write those functions as there's no such notion as property.
I warn you, it is not fully compatible native C++: Microsoft-specific C++ only.
The Microsoft compiler allows you to use declspec(property), this way:
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
// here you define the property and the functions to call for it
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5; // THERE YOU GO
return s.the_prop;
}
cf Microsoft Documentation for more details: declspec(property).
Moo-Juice's answer looks really cool, but has a drawback: you can't use these properties like normal expressions of type T, as you can in C#.
For instance,
a.text.c_str() won't compile (‘class Property<std::basic_string<char> >’ has no member named ‘c_str’)
std::cout << a.text won't compile either (template argument deduction/substitution failed)
I would suggest the following enhancement to template<typename T> class Property:
T& operator() ()
{
return _value;
}
T const& operator() () const
{
return _value;
}
Then you can access the property's members with (), such as:
char const *p = a.text().c_str();
And you can use the property in expressions where the type must be deduced:
std::cout << a.text();
A property in .NET is associated with a get and/or a set member function, so it's really just syntactic sugar. The closest you can get with C++ is to use overloading to give the getter and setter the same name:
const std::string &test() const { return text_; }
void test(const std::string &value) { text_ = value; }
Obviously, you will still have to provide parenthesis for the call:
someThing.text("blah");
String blah = someThing.text();
Yes but it's vendor specific. Microsoft has declspec(property).
C++Builder's implementation is a bit more advanced (via vendor specific __property keyword) in that you could have indexed accessors (which can be of any types you wish).
Also check this out (without relying on vendor specific keywords): http://www.codeproject.com/KB/cpp/cpp_property_indexer.aspx
#include <iostream>
#include <string>
using namespace std;
// ------------------------------------------------------------------
#define PROPERTY_GET_SET(CLASS, NAME, TYPE) GetSetProperty<CLASS, TYPE> NAME() { return GetSetProperty<CLASS, TYPE>(this, &CLASS::get_##NAME, &CLASS::set_##NAME); }
#define PROPERTY_GET(CLASS, NAME, TYPE) GetProperty<CLASS, TYPE> NAME() { return GetProperty<CLASS, TYPE>(this, &CLASS::get_##NAME); }
#define PROPERTY_SET(CLASS, NAME, TYPE) SetProperty<CLASS, TYPE> NAME() { return SetProperty<CLASS, TYPE>(this, &CLASS::set_##NAME); }
template <typename CLASS, typename TYPE>
struct GetSetProperty {
typedef TYPE (CLASS::*Getter_t)() const;
typedef void (CLASS::*Setter_t)(TYPE);
GetSetProperty(CLASS* instance, Getter_t getter, Setter_t setter) : m_instance(instance), m_getter(getter), m_setter(setter) {}
operator TYPE() const { return (this->m_instance->*this->m_getter)(); }
GetSetProperty<CLASS, TYPE>& operator=(TYPE value) { (this->m_instance->*this->m_setter)(value); return *this; }
CLASS* const m_instance;
const Getter_t m_getter;
const Setter_t m_setter;
};
template <typename CLASS, typename TYPE>
struct GetProperty {
typedef TYPE (CLASS::*Getter_t)() const;
GetProperty(CLASS* instance, Getter_t getter) : m_instance(instance), m_getter(getter) {}
operator TYPE() const { return (this->m_instance->*this->m_getter)(); }
CLASS* const m_instance;
const Getter_t m_getter;
};
template <typename CLASS, typename TYPE>
struct SetProperty {
typedef void (CLASS::*Setter_t)(TYPE);
SetProperty(CLASS* instance, Setter_t setter) : m_instance(instance), m_setter(setter) {}
SetProperty<CLASS, TYPE>& operator=(TYPE value) { (this->m_instance->*this->m_setter)(value); return *this; }
CLASS* const m_instance;
const Setter_t m_setter;
};
template <typename CLASS, typename TYPE>
ostream& operator<<(ostream& ostr, const GetSetProperty<CLASS, TYPE>& p) { ostr << (p.m_instance->*p.m_getter)(); return ostr; }
template <typename CLASS, typename TYPE>
ostream& operator<<(ostream& ostr, const GetProperty<CLASS, TYPE>& p) { ostr << (p.m_instance->*p.m_getter)(); return ostr; }
// ------------------------------------------------------------------
class Dummy
{
public:
Dummy() : m_value1(42) {}
PROPERTY_GET_SET(Dummy, Value1, int);
PROPERTY_GET_SET(Dummy, Value2, const string&);
protected:
virtual int get_Value1() const { return this->m_value1; }
virtual void set_Value1(int value) { this->m_value1 = value; }
virtual const string& get_Value2() const { return this->m_value2; }
virtual void set_Value2(const string& value) { this->m_value2 = value; }
private:
int m_value1;
string m_value2;
};
int main(int argc, char* argv[]) {
Dummy d;
cout << d.Value1() << endl;
d.Value1() = 3;
cout << d.Value1() << endl;
cout << d.Value2() << endl;
d.Value2() = "test";
cout << d.Value2() << endl;
return 0;
}
// ------------------------------------------------------------------
By using std::function you can get pretty close. Featurewise everything is here.
First create the templated Property class:
#include <functional>
template<class T>
class Property
{
std::function<T (void)> _get;
std::function<void(const T&)> _set;
public:
Property(
std::function<T (void)> get,
std::function<void(const T&)> set)
: _get(get),
_set(set)
{ }
Property(
std::function<T(void)> get)
: _get(get),
_set([](const unsigned int&){})
{ }
operator T () const { return _get(); }
void operator = (const T& t) { _set(t); }
};
Use the Property in a class by creating a get and a set method similar to what you would in do C#:
class Test
{
private:
std::string _label;
public:
Property<std::string> Label = Property<std::string>
(
[this]()->std::string
{
return this->_label;
},
[this](const std::string& value)
{
this->_label = value;
}
);
Property<unsigned int> LabelSize = Property<unsigned int>
(
[this]()->unsigned int
{
return this->_label.size();
}
);
};
Testing this code:
Test test;
test.Label = "std functional";
std::cout << "label = " << std::string(test.Label) << std::endl
<< "label size = " << int(test.LabelSize) << std::endl;
will output
label = std functional
label size = 14
I think this is as syntactic-sugar-coated as you can get it in c++ :)
Probably the best option currently is to use the microsoft's __declspec( property( get=get_func_name, put=put_func_name ) ) PropertyType PropertyName attribute.
it is also supported by clang,
it is converted into your getter/setter when compiled (won't add any new variables),
in use, it is the closest thing to a real property (can access property of a property...).
But if you're using other compilers, you could use macros:
#define PROPERTY_GEN(Class, Type, Name, GetMethod, SetMethod) \
class Property_##Name { \
public: \
Property_##Name(Class* parent) : _parent(parent) { } \
Type operator = (Type value) \
{ \
_parent->SetMethod(value); \
return _parent->GetMethod(); \
} \
operator Type() const \
{ \
return static_cast<const Class*>(_parent)->GetMethod(); \
} \
Property_##Name& operator =(const Property_##Name& other) \
{ \
operator=(other._parent->GetMethod()); return *this; \
}; \
Property_##Name(const Property_##Name& other) = delete; \
private: \
Class* _parent; \
} Name { this };
// PROPERTY - Declares a property with the default getter/setter method names.
#define PROPERTY(Class, Type, Name) \
PROPERTY_GEN(Class, Type, Name, get_##Name, set_##Name)
Then use them like:
class SomeClass
{
public:
PROPERTY(SomeClass, int, Value)
int get_Value() const { return _value; }
void set_Value(int value) { _value = value; }
private:
int _value = 0;
};
int main()
{
SomeClass s, c;
s.Value = 5;
c.Value = 3 * s.Value;
s.Value = c.Value;
}
You could also add other macro variants for read-only, write-only properties and read-only non-const getters. To be able to access sub-properties via ->, you could add operator-> overloads to the macro.
Compared to microsoft's __declspec(property(...)), getter and setter methods can be made private but this isn't a real advantage since client might need to take the address of a getter/setter sometimes.
There is also a disadvantage of having an additional _parent variable for every property, and you would need to explicitly define copy constructors for parent classes if they are used.
I realize it's this question is probably too old to add another answer but to expand on Moo-Juice's answer, I've come up with a pretty neat and simple solution:
/// Utility for functions get, set & ptr.
template<typename TVal>
using GetFn = std::function<const TVal& (void)>;
template<typename TVal>
using SetFn = std::function<void(const TVal&)>;
template<typename TVal>
using PtrFn = std::function<TVal* (void)>;
/// The property class and each specialization utility.
template<typename TVal, bool Delegate, bool ReadOnly>
class Property;
template<typename TVal>
using PropertyGetSet = Property<TVal, false, false>;
template<typename TVal>
using PropertyDelGetSet = Property<TVal, true, false>;
template<typename TVal>
using PropertyGet = Property<TVal, false, true>;
template<typename TVal>
using PropertyDelGet = Property<TVal, true, true>;
/// <summary>
/// Property get-set.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, false, false>
{
public:
typedef TVal Value;
Property(const TVal& val)
: m_value(val)
{}
inline const TVal& Get() const { return m_value; }
inline void Set(const TVal& val) { m_value = val; }
inline TVal* Ptr() { return &m_value; }
private:
TVal m_value;
};
/// <summary>
/// Property delegate get-set.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, true, false>
{
public:
typedef TVal Value;
Property(GetFn<TVal> getFn, SetFn<TVal> setFn, PtrFn<TVal> ptrFn)
: m_getFn(getFn)
, m_setFn(setFn)
, m_ptrFn(ptrFn)
{}
inline const TVal& Get() const { return m_getFn(); }
inline void Set(const TVal& val) { m_setFn(val); }
inline TVal* Ptr() { return m_ptrFn(); }
private:
GetFn<TVal> m_getFn;
SetFn<TVal> m_setFn;
PtrFn<TVal> m_ptrFn;
};
/// <summary>
/// Property get.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, false, true>
{
public:
typedef TVal Value;
Property(const TVal& val)
: m_value(val)
{}
inline const TVal& Get() const { return m_value; }
inline TVal* Ptr() { return &m_value; }
private:
TVal m_value;
};
/// <summary>
/// Property delegate get.
/// </summary>
/// <typeparam name="TVal">Value type.</typeparam>
template<typename TVal>
class Property<TVal, true, true>
{
public:
typedef TVal Value;
Property(GetFn<TVal> getFn, PtrFn<TVal> ptrFn)
: m_getFn(getFn)
, m_ptrFn(ptrFn)
{}
inline const TVal& Get() const { return m_getFn(); }
inline TVal* Ptr() { return m_ptrFn(); }
private:
GetFn<TVal> m_getFn;
PtrFn<TVal> m_ptrFn;
};
And then to use it:
PropertyGetSet<std::string> strGetSet = PropertyGetSet<std::string>("GetSet");
std::string m_strGetSet = "DelGetSet";
PropertyDelGetSet<std::string> strDelGetSet =
PropertyDelGetSet<std::string>(
[&]() -> const std::string& { return m_strGetSet; },
[&](const std::string& val) { m_strGetSet = val; },
[&]() { return &m_strGetSet; /* throw? */ });
// The get (read-only) version is the same but without the set function
Some caveats:
The get function returns a const& so you are not able to use it for changing the value, this is by design as it would allow people to use the reference to set the value instead of the explicit Set which gives the advantage of knowing when the value is set.
There is no syntactic sugar for the get-set-ptr functions, personally, I didn't like using operators cause it made the underlying system more obtuse, so using explicit functions lets the user know that it's a property and not something else. But if you may, you could sprinkle some operator overloads.
All specializations have a Ptr function which will be the pointer of the data. However, when using the delegate version, you can choose to throw so anyone trying to use it will have to work around it. The reason it's there is that in the worst-case scenario you may try to use the pointer for a very particular situation, I would highly advise not to use this tho, so feel free to remove it or make an extra specialization for it.
Lastly, it's a bit verbose, you could wrap the usage in a macro to make the syntax a bit shorter, but personally, I like it the way it is as it's more explicit that way.
EDIT:
You may run into the same issue I had with this design, have a look at the following link for the issue and the solution I've come up with: https://stackoverflow.com/a/68563492/3339838
Another try to enhance Moo-Juice's answer, by defining a Getter class (which the client can only get) and a Getter-Setter class which is also assignable:
template <typename T>
class Getter {
protected:
T &_value;
public:
Getter(T &value) : _value(value) {}
operator const T() const {
return _value;
}
};
template <typename T>
class GetterSetter : public Getter<T> {
using Getter<T>::_value;
using Getter<T>::Getter;
public:
GetterSetter<T> & operator=(const T val) {
_value = val;
return *(this);
}
};
This gives you the option to decide which properties could be changed from outside the class, and which will only change internally.
No, there is not. You would just create getter and setter functions:
someThing.setText("blah");
std::string blah = someThing.getText();