Related
Suppose I have the following very simple class:
class A
{
public:
static constexpr A make() { return A{}; }
constexpr A() : _v(0) {}
constexpr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
If I try to use it as follows:
int main()
{
volatile A a1;
a1.setV(10);
//OR
//The optimizer will optimize this chain of constexpr calls into a single "store" instruction
a1 = A::make().setV(10); //More chaining here
return 0;
}
The code will not compile.
I understand why this is true based upon: Defining volatile class object
I know that the solution would be to add an additional method like so:
class A
{
public:
constexpr A() : _v(0) {}
volatile A& setV(int v) volatile { _v = v; return *this; }
constepxr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
As an aside, I am aware that returning the volatile reference will issue a warning if it is not used.
My question is, is there any way I can avoid code duplication in this case? Both implementations of setV will always be the same. Thus, if I add/change more methods, I have to maintain them both which could get messy if they aren't so trivial. The only difference is one of type qualifiers...
Since there have been some mentions of this in the comments, I thought I would note that I need volatile here because I am attempting to eventually implement "class overlay" for hardware peripheral register access on an embedded system.
In C++23, you can use an explicit object parameter (also known as deducing this) for this purpose:
class A
{
public:
A() : _v(0) {}
template <class Self>
constexpr auto&& setV(this Self&& self, int v) {
self._v = v; return self;
}
private:
int _v;
};
Unfortunately, as of this writing the only compiler that supports this is the latest version of Microsoft Visual C++.
I came up with one possible solution. It's dubious whether it's less verbose than what I had before, but at least I don't have to duplicate the body of the method. In fact, it's similar (in my mind) to the proposed C++23 answer by #ComicSansMS.
class A
{
public:
constexpr A() : _v(0) {}
template <typename T>
static constexpr void setV(T& dest, int src) { dest = src; }
volatile A& setV(int v) volatile { setV(_v, v); return *this; }
constepxr A& setV(int v) { setV(_v, v); return *this; }
private:
int _v;
};
T will be deduced as either int& or volatile int& depending on the context. Since its declare constexpr/inline, the compiler/optimizer still boils it down to a few assembly instructions.
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();
In C++ I'm often facing a situation when I need to prepare const and non-const version of class in analogy to const_iterator and iterator from standard library.
class const_MyClass
{
public:
const_MyClass(const int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
private:
const int * m_arr;
}
class MyClass
{
public:
MyClass(int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
void modify(int i); //modify m_arr
private:
int * m_arr;
}
The problem with this is that I need to repeat whole code of const_MyClass in MyClass and distribute any changes in API to both classes. Thus sometimes I inherit const_MyClass and do some const_casts, which also isn't perfect and pretty solution. Still when I want to pass const_MyClass instance by reference it looks moronic:
void func(const const_MyClass & param)
Instance param is marked with two "consts", and it has only const methods...
This is where const constructors would be handy, but are there any existing alternatives?
Some use examples to explain problem better:
//ok to modify data
void f(int * data)
{
MyClass my(data);
my.modify();
...
}
//cant modify data, cant use MyClass
void fc(const int * data)
{
const_MyClass my(data);
int i = my.method();
...
}
You can make a template class to act as a base, like this:
template<typename T>
class basic_MyClass
{
public:
basic_MyClass(T * arr) :m_arr(arr) {}
int method() const; //does something with m_arr without modifying it
private:
T * m_arr;
};
Then, for your const version, since it doesn't add anything, you can just use a typedef:
typedef basic_MyClass<const int> const_MyClass;
For your non-const version, you can inherit:
class MyClass : public basic_MyClass<int>
{
public:
using basic_MyClass::basic_MyClass; // inherit all the constructors
void modify(int i); //modify m_arr
};
Have you considered simply tracking two pointers and raising exceptions from the mutable operations when no mutable value is available? Maybe an example will help describe what I am thinking of.
class MyClass
{
public:
MyClass(int *mutable_data):
m_mutable_view(mutable_data), m_readonly_view(mutable_data)
{
}
MyClass(const int *immutable_data):
m_mutable_view(NULL), m_readonly_view(immutable_data)
{
}
int retrieve_value(int index) {
return m_readonly_view[index];
}
void set_value(int index, int value) {
require_mutable();
m_mutable_view[index] = value;
}
protected:
void require_mutable() {
throw std::runtime_error("immutable view not available");
}
private:
const int *m_readonly_view;
int *m_mutable_view;
};
The idea is pretty simple here - use a sentinel value to indicate whether modifications are possible or not instead of depending on the type system to do that for you. Personally, I would think about doing the inheritance based approach that #BenjaminLindley suggested but I wanted to present a slightly different solution that might not have occurred to you.
After talk with Neil Kirk I realized what I was doing wrong. I started by separating data from logic as he suggested.
This attempt resulted in two classes MyClassPtr and const_MyClassPtr. They only provide functions for data access (like iterators) and may look like that:
class const_MyClassPtr
{
public:
const_MyClassPtr(const int * arr);
int operator [](int i) const;
const int * ptr() const;
private:
const int * m_arr;
}
class MyClassPtr
{
public:
MyClassPtr(int * arr);
int operator [](int i) const;
int & operator [](int i);
const int * ptr() const;
int * ptr();
//promotion to const pointer
const_MyClassPtr () const {return const_MyClassPtr(m_arr);}
private:
int * m_arr;
}
Now it is clear that objects of these classes should be treated like pointers, so when I use them as function parameters I pass them by value!
void func(const_MyClassPtr param) //instead of void func(const const_MyClass & param)
To provide methods I have created MyClassOp class template and used static polymorphism.
template <class DERIVED>
class MyClassOp
{
public:
const DERIVED & derived() const {return static_cast<const DERIVED &>(*this)}
DERIVED & derived() {return static_cast<DERIVED &>(*this)}
int method() const; //operates on derived() const
void modify(int i); //operates on derived()
}
MyClassOp is a collection of methods. It does not have state. In general it is a trait. To make these methods accessible I overloaded -> and * operators
class const_MyClassPtr : private MyClassOp<const_MyClassPtr>
{
public:
const MyClassOp<MyClassPtr> * operator ->() const {return this;}
const MyClassOp<MyClassPtr> & operator *() const {return *this;}
...
}
class MyClassPtr : private MyClassOp<MyClassPtr>
{
public:
MyClassOp<MyClassPtr> * operator ->() {return this;}
MyClassOp<MyClassPtr> & operator *() {return *this;}
...
}
This works O.K., but is a bit cumbersome. If I have for example equality operator I need to write something like *myptr1 == myptr2 to compare values kept by two MyClassPtr objects (it's easy to make a mistake and compare myptr1 == myptr2 or expect that something like *myptr1 == *myptr2 could work). Also when I have allocating type:
class MyClass : public MyClassOp<MyClass>
{
MyClass(int x, int y, int z);
...
int m_arr[3];
}
I would want to be able to use temporaries as function arguments.
void f(const_MyClassPtr my);
//use temporary when calling f()
f(MyClass(1, 2, 3));
I can do this by providing conversion operators or conversion constructors (that convert MyClass to const_MyClassPtr). But then const_MyClassPtr behaves more like reference than pointer. If iterators are generalization of pointers then why one could not imitate reference? Therefore I divided MyClassOp into two parts (const and non const) and replaced -> and * operators implemented by const_MyClassPtr and MyClassPtr with public inheritance and changed their names to ressemble reference. I ended up with following structures.
MyClassOp : public const_MyClassOp
const_MyClassRef : public const_MyClassOp<const_MyClassRef>
MyClassRef : public MyClassOp<MyClassRef>
MyClass : public MyClassOp<MyClass>
However const_MyClassRef and MyClassRef are not perfect generalization of reference as it impossible to imitate some of C++ reference properties, so Ref suffix is there to denote reference-like structure.
Maybe you can find some hints in effective c++ item 4 "Avoid duplication in const and non-const Member function"
I may summarize like following ( it makes you avoid code duplication even if using somewhat ugly cast ):
struct my_class
{
my_class(int x):_x(x){};
const int& method(void) const;
int& method(void);
int _x;
};
const int& my_class::method(void) const //func for const instance
{
return _x;
}
int& my_class::method(void) //func for normal instance
{
return const_cast<int& >(static_cast<const my_class& >(*this).method()) ;
}
int main()
{
my_class a(1);
const my_class b(2);
a.method() = 5;
cout << a.method() << endl;
//b.method() = 4; //b is const, wont compile
cout << b.method() << endl;
return 0;
}
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 would like to combine setter/getter in one method, in C++, in order to be able to do the following:
Foo f;
f.name("Smith");
BOOST_CHECK_EQUAL("Smith", f.name());
I don't know how can I declare such a method inside Foo class:
class Foo {
public:
// how to set default value??
const string& name(const string& n /* = ??? */) {
if (false /* is it a new value? */) {
_name = n;
}
return _name;
}
private:
string _name;
}
I'm looking for some elegant solution, with a true C++ spirit :) Thanks!
class Foo {
public:
const string& name() const {
return name_;
}
void name(const string& value) {
name_ = value;
}
private:
string name_;
};
You can create a second method with different parameters, in this case none to simulate a default parameter:
string& name() {
// This may be bad design as it makes it difficult to maintain an invariant if needed...
// h/t Matthieu M., give him +1 below.
return _name;
}
And if you need a const getter, just add it as well!
const string& name() const {
return _name;
}
The compiler will know which one to call, that's the magic of overloading.
Foo f;
f.name("Smith"); // Calls setter.
BOOST_CHECK_EQUAL("Smith", f.name()); // Calls non-const getter.
const Foo cf;
BOOST_CHECK_EQUAL("", cf.name()); // Calls const getter.
I would not advise trying to do this, because then you can't make your "get" functions const. This would work, but it would totally break when someone has a const Foo and wants to execute GetA(). For that reason, I advise separate functions and a const GetA().
class Foo
{
int _a;
static int _null;
public:
const int& a(const int& value = _null) {
if (&value != &_null)
_a = value;
return _a;
}
};