Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
is there any generic way to take an existing class, and "constify" it by removing all non-const functionality?
One possible workaround is to create a wrapper class that holds an instance of the class and only gives access to a const reference to it.
template<class T>
class Immutable {
public:
template<typename... Args>
Immutable(Args&&... args) : instance(forward<Args>(args)...) {
}
operator const T&() {
return instance;
}
const T& get() const {
return instance;
}
private:
Immutable& operator=(const Immutable& other) = delete;
T instance;
};
Suppose you have a mutable class Class:
class Class {
public:
Class() : m_value(0) {
}
Class(const Class& other) : m_value(other.m_value) {
}
Class(int value) : m_value(value) {
}
Class(int x, int y) : m_value(x + y) {
}
void change(int value) {
m_value = value;
}
int value() const {
return m_value;
}
private:
int m_value;
};
Here is how Immutable<Class> can be used:
void functionTakingConstReference(const Class& x) {
}
void functionTakingNonConstReference(Class& x) {
}
void functionTakingImmutableClass(Immutable<Class>& x) {
}
void functionTakingValue(Class x) {
}
int main(int argc, char *argv[])
{
// Any constructor of Class can also be used with Immutable<Class>.
Immutable<Class> a;
Immutable<Class> b(1);
Immutable<Class> c(2, 3);
Immutable<Class> d(c);
// Compiles and works as expected.
functionTakingConstReference(a);
functionTakingImmutableClass(a);
functionTakingValue(a);
cout << a.get().value() << endl;
// Doesn't compile because operator= is deleted.
// b = a;
// Doesn't compile because "change" is a non-const method.
// a.get().change(4);
// Doesn't compile because the function takes a non-const reference to Class as an argument.
// functionTakingNonConstReference(a);
return 0;
}
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
No.
But you can declare all members as const. Then both const and non-const instances would behave largely in the same way and it shouldn't matter whether the instances are const.
I think you are looking for an immutable class. An easy way to get immutability is to declare all member variables as const. This way you ensure that the state of your objects will not change after construction.
This guarantee is independent of whether your object is const and even if you have non-const member functions for that class.
For example:
class Foo
{
public:
Foo(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
private:
const int m_id;
const double m_value;
};
Another way you could generate an immutable object of any type is through a template class. Something like this:
class Bar
{
public:
Bar(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
void SetId(int id) { m_id = id; }
private:
int m_id;
double m_value;
};
template<typename T>
class MyImmutable
{
public:
const T m_obj;
MyImmutable(const T& obj) : m_obj(obj)
{ }
};
int main()
{
cout << "Hello World!" << endl;
Foo a(1,2.0);
Bar x(2,3.0);
MyImmutable<Bar> y(x);
cout << "a.id = " << a.Id() << endl;
cout << "a.value = " << a.Value() << endl;
cout << "y.id = " << y.m_obj.Id() << endl;
cout << "y.value = " << y.m_obj.Value() << endl;
y.m_obj.SetId(2); // calling non-const member throws an error.
return 0;
}
Related
I have a template:
template<typename T>
struct Parameter {
T value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
// Fix this->value (make this->value const)
}
void print() { std::cout << value << std::endl; }
};
and I would like at some point after initialization to 'const-ify' the value variable
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance.value = 2.3; // Not Allowed, throws error
Is it possible to do so and how?
If you want to maintain the same interface, and marshalling access to value through accessors is something you want to avoid, then you could isolate the "fixable" feature in its own dedicated type that implicitly converts to/from T:
template<typename T>
class fixable {
bool fixed_ = false;
T val_;
public:
fixable() = default;
fixable(T v) : val_(v) {}
fixable(const fixable&) = default;
fixable(fixable&&) = default;
operator const T&() const {
return val_;
}
fixable& operator=(const T& v) {
if(fixed_ ) {
throw std::runtime_error("Fixable has been fixed");
}
val_ = v;
return *this;
}
void fix() {
fixed_ = true;
}
};
You would then replace the T member with a fixable<T> within Parameter:
template<typename T>
struct Parameter {
fixable<T> value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
value.fix();
}
void print() { std::cout << value << std::endl; }
};
The main function from your question can remain exactly as-is.
You can use something like this:
Similar to abowe answer but with boolean inside the Parameter struct
template<typename T>
struct Parameter {
Parameter(std::string name, T value) : name(name), value(value), bFixed(false) {}
void fix() {
bFixed = true;
}
void print() { std::cout << value << std::endl; }
Parameter& operator=(const T& oValue)
{
if (bFixed)
{
throw std::runtime_error("Error fixed value..");
}
value = oValue;
return *this;
}
std::string name;
private:
bool bFixed;
T value;
};
int main()
{
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance = 2.3; // Not Allowed, throws error
}
You cannot change a member variable from const to non-const. However, you can create a new object in which it is const. For example:
template<typename T>
struct example {
T value;
example<T const> fix() && {
return {value};
}
};
int main(){
auto x = example<int>{1};
x.value = 4; // OK
auto y = std::move(x).fix();
y.value = 7; // error: assignment of read-only member
}
The presence of && forces the use of std::move which makes it obvious that x should no longer be used.
As far as I know, this seems to be impossible in a straightforward way. Making the member const makes it const for everyone. I would like to have a read-only property, but would like to avoid the typical "getter". I'd like const public, mutable private. Is this at all possible in C++?
Currently all I can think of is some trickery with templates and friend. I'm investigating this now.
Might seem like a stupid question, but I have been surprised by answers here before.
A possible solution can be based on an inner class of which the outer one is a friend, like the following one:
struct S {
template<typename T>
class Prop {
friend struct S;
T t;
void operator=(T val) { t = val; }
public:
operator const T &() const { return t; }
};
void f() {
prop = 42;
}
Prop<int> prop;
};
int main() {
S s;
int i = s.prop;
//s.prop = 0;
s.f();
return i, 0;
}
As shown in the example, the class S can modify the property from within its member functions (see S::f). On the other side, the property cannot be modified in any other way but still read by means of the given operator that returns a const reference to the actual variable.
There seems to be another, more obvious solution: use a public const reference member, pointing to the private, mutable, member. live code here.
#include <iostream>
struct S {
private:
int member;
public:
const int& prop;
S() : member{42}, prop{member} {}
S(const S& s) : member{s.member}, prop{member} {}
S(S&& s) : member(s.member), prop{member} {}
S& operator=(const S& s) { member = s.member; return *this; }
S& operator=(S&& s) { member = s.member; return *this; }
void f() { member = 32; }
};
int main() {
using namespace std;
S s;
int i = s.prop;
cout << i << endl;
cout << s.prop << endl;
S s2{s};
// s.prop = 32; // ERROR: does not compile
s.f();
cout << s.prop << endl;
cout << s2.prop << endl;
s2.f();
S s3 = move(s2);
cout << s3.prop << endl;
S s4;
cout << s4.prop << endl;
s4 = s3;
cout << s4.prop << endl;
s4 = S{};
cout << s4.prop << endl;
}
I like #skypjack's answer, but would have written it somehow like this:
#include <iostream>
template <class Parent, class Value> class ROMember {
friend Parent;
Value v_;
inline ROMember(Value const &v) : v_{v} {}
inline ROMember(Value &&v) : v_{std::move(v)} {}
inline Value &operator=(Value const &v) {
v_ = v;
return v_;
}
inline Value &operator=(Value &&v) {
v_ = std::move(v);
return v_;
}
inline operator Value& () & {
return v_;
}
inline operator Value const & () const & {
return v_;
}
inline operator Value&& () && {
return std::move(v_);
}
public:
inline Value const &operator()() const { return v_; }
};
class S {
template <class T> using member_t = ROMember<S, T>;
public:
member_t<int> val = 0;
void f() { val = 1; }
};
int main() {
S s;
std::cout << s.val() << "\n";
s.f();
std::cout << s.val() << "\n";
return 0;
}
Some enable_ifs are missing to really be generic to the core, but the spirit is to make it re-usable and to keep the calls looking like getters.
This is indeed a trickery with friend.
You can use curiously recurring template pattern and friend the super class from within a property class like so:
#include <utility>
#include <cassert>
template<typename Super, typename T>
class property {
friend Super;
protected:
T& operator=(const T& val)
{ value = val; return value; }
T& operator=(T&& val)
{ value = val; return value; }
operator T && () &&
{ return std::move(value); }
public:
operator T const& () const&
{ return value; }
private:
T value;
};
struct wrap {
wrap() {
// Assign OK
prop1 = 5; // This is legal since we are friends
prop2 = 10;
prop3 = 15;
// Move OK
prop2 = std::move(prop1);
assert(prop1 == 5 && prop2 == 5);
// Swap OK
std::swap(prop2, prop3);
assert(prop2 == 15 && prop3 == 5);
}
property<wrap, int> prop1;
property<wrap, int> prop2;
property<wrap, int> prop3;
};
int foo() {
wrap w{};
w.prop1 = 5; // This is illegal since operator= is protected
return w.prop1; // But this is perfectly legal
}
Next code presents class-parameter-wrapper, it allows to access underlying class via getters and setters. Simplified version:
template<typename T>
class Parameter
{
public:
typedef T value_type;
typedef Parameter<T> Type;
protected:
T value_;
public:
Parameter() { this->value_ = this->default_value(); }
Parameter(T&& val) { this->set(std::forward<T>(val)); }
Parameter(const T& val) { this->set(std::forward<T>(val)); }
virtual ~Parameter() {};
// Get
T& get() { return this->value_/*this->getter()*/; }
operator T&() { return this->get(); }
// Set
Type& set(T&& val)
{
std::cout << "T&& setter called with " << val << std::endl;
value_ = this->setter(std::forward<T>(val));
return *this;
}
Type& set(const T& val)
{
std::cout << "constT& setter called with " << val << std::endl;
value_ = this->setter(std::forward<const T>(val));
return *this;
}
Type& operator=(T const& val) { return this->set(val); }
Type& operator=(T&& val) { return this->set(val); }
virtual T setter(T const& val) { return val; }
virtual const T& default_value()
{
static const T default_value_{};
return default_value_;
};
};
Using:
int main()
{
struct IncrementorPar : Parameter<int>
{
using Parameter::Parameter; //todo HIDE
using Parameter::operator=; //todo HIDE
virtual int setter(int const& val) { return val + 1; }
virtual const int& default_value(){ return -1; };
} in1(1), in2 = 2, int0;
//assert(int0==int0.default_value()); //FAIL
//assert(int0==-1); //FAIL
//assert(in1 == 2); //FAIL
//assert(in2 == 3); //FAIL
auto *pi1 = new IncrementorPar(2);
//assert(*pi1==3); //FAIL
pi1->set(2);
assert(*pi1==3);
*pi1 = 33;}
}
How could it be possible to call descendant's methods setter() and default_value() from ancestor's constructor?
How can I hide using's?
Not really an elegant solution but...
You could postpone the initialization of value_ using a init() function.
Something like
template<typename T>
class Parameter
{
private:
bool toInit { true };
bool initWithVal;
T valInit;
void init ()
{
if ( initWithVal )
this->set(valInit);
else
value_ = this->default_value();
toInit = false;
}
public:
typedef T value_type;
typedef Parameter<T> Type;
protected:
T value_;
public:
Parameter() : initWithVal{false} { }
Parameter(T&& val) : initWithVal{true}, valInit{std::move(val)} { }
Parameter(const T& val) { this->set(std::forward<T>(val)); }
virtual ~Parameter() {};
// Get
T& get() { if ( toInit ) init(); return this->value_/*this->getter()*/; }
operator T&() { return this->get(); }
// Set
Type& set(T&& val)
{
toInit = false;
std::cout << "T&& setter called with " << val << std::endl;
value_ = this->setter(std::forward<T>(val));
return *this;
}
Type& set(const T& val)
{
toInit = false;
std::cout << "constT& setter called with " << val << std::endl;
value_ = this->setter(std::forward<const T>(val));
return *this;
}
Type& operator=(T const& val) { return this->set(val); }
Type& operator=(T&& val) { return this->set(val); }
virtual T setter(T const& val) { return val; }
virtual const T& default_value()
{
std::cout << "base default value\n";
static const T default_value_{};
return default_value_;
};
};
Explanation
It's not possible to call descendant's methods from ancestor's, without overriding the constructor of each derived class, as during construction, the vtable has information on only the so-far-constructed classes, in the order of constructor calls (which as we recall, is base -> most derived).
Excerpt аrom the forum:
I have a class which calls from its constructor a virtual method Init().
In the descendants I override this virtual method Init(). And the idea is
that whenever I create a descendant, I want the descendant's Init() to be
called, not the ancestors! And I dont want to override the constructor for
that, because I'd have to override the constructors of every descendants
then. How is it possible?
answer
It's not possible without overriding the constructor of each derived class,
as during construction, the vtable has information on only the
so-far-constructed classes, in the order of constructor calls (which as we
recall, is base -> most derived). So when ClassA's constructor gets called,
despite it being an instance of ClassB, the virtual function mechanism will
have access to ClassB's overrides for ClassA's functions only after
ClassA's constructor has finished executing, so anytime you call a virtual
function from ClassA::ClassA(), ClassA::Init() will be called.
-- Dan
Solution
use init guides-variables as #max66 suggested, or something similar.
I wonder how to hide a real property field (not make it private or public but force to use setters and getters) and provide him with simple setter and getter. So I wonder how to create api like:
private:
Property( int my_a);
public:
Property( int my_b);
...
{
set_my_a(1);
cout << get_my_a() << endl;
// my_a = 13; // will cause compiler error
...
How to create such thing via Boost preprocessor?
Do you really need to use boost preprocessor?
you have a solution without boost below:
// property.h
#include <stdio.h>
#define property(type) struct : public Property <type>
template <typename T>
class Property
{
protected:
T value;
public:
virtual T get() {
return value;
}
virtual void set(T new_value) {
value = new_value;
}
};
usage example:
// test.cpp
#include "property.h"
class Test {
public:
property(int) {} a;
property(int) {
int get() {
return value * 10;
}
} b;
property(int) {
void set(int x) {
value = x * 200;
}
} c;
property(int) {
int get() {
return value * 3000;
}
void set(int x) {
value = x * 443;
}
} d;
};
main()
{
Test t;
printf("i\ta\tb\tc\td\t\n");
for (int i=0; i<10; i++) {
t.a.set(i);
t.b.set(i);
t.c.set(i);
t.d.set(i);
printf("%i\t%i\t%i\t%i\t%i\n", i, t.a.get(), t.b.get(), t.c.get(), t.d.get());
}
}
The wikipedia solution in http://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B is good but needs a minimal modification to become useful, because without the protected statement you cant write your own getters and setters.
#include <iostream>
template <typename T>
class property {
protected:
T value;
public:
T & operator = (const T &i) {
::std::cout << i << ::std::endl;
return value = i;
}
operator T const & () const {
return value;
}
};
struct Bar {
property <bool> alpha;
struct :public property <int> {
int & operator = (const int &i) {
::std::cout << "new setter " << i << ::std::endl;
return value = i;
}
} bravo;
};
main()
{
Bar b;
b.alpha = false;
b.bravo = (unsigned int) 1;
}
You can change a little more if you want:
#include <iostream>
#define SETTER(type) public: type& operator=(const type new_value)
#define GETTER(type) public: operator type const & () const
template <typename T>
class Property {
protected:
T value;
public:
T & operator = (const T &i) {
::std::cout << i << ::std::endl;
return value = i;
}
template <typename T2> T2 & operator = (const T2 &i) {
::std::cout << "T2: " << i << ::std::endl;
T2 &guard = value;
throw guard; // Never reached.
}
operator T const & () const {
return value;
}
};
struct Bar {
Property <bool> alpha;
struct:Property <int> {
SETTER(int) {
value = new_value * 1000;
::std::cout << "new method " << new_value << ::std::endl;
return value;
}
GETTER(int) {
return value/1000;
}
} bravo;
};
main()
{
Bar b;
b.alpha = false;
b.bravo = (unsigned int) 1;
::std::cout << b.bravo << ::std::endl;
}
Rather than rewrite an example of the implementation, this is the link for one on Wikipedia: http://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
This basically forces the property to be accessed through getter/setter methods. The upgrade you would need to get your desired effect is the ability to pass functors to these properties. There are plenty of ideas on implementing these; the best approach I cannot advise and depends on your developmental needs. Personally, it feels like over engineering and prefer to just use Pimpl to hide my private details and just provide the getters/setters explicitly.
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;
}