struct with const member
Solution 1
Here's a way to "expose" a public, read-only data member that is modifiable by the class's own member functions (including assignment):
template <typename T>
class Helper {
friend class A;
T *ptr;
Helper &operator=(const Helper &rhs) = default; // in C++11
Helper &operator=(const Helper &rhs) { ptr = rhs.ptr; } // in C++03
public:
Helper(T *ptr) : ptr(ptr) {}
operator const int &() const { return *ptr; }
};
class A {
int v1_;
public:
Helper<int> v1;
A() : v1(&v1_) {} // although `A` should have a constructor that sets `v1_`
A(const A &rhs) { v1_ = rhs.v1_; v1 = Helper<int>(&v1_); }
A &operator=(const A &rhs) { v1_ = rhs.v1_; v1 = Helper<int>(&v1_); }
};
Now anyone outside the class A can use v1
, but the only thing they can use it for is to get a const int&
reference to v1_
.
It is far easier just to give A
a getter function that returns const int &
, but if you really want the data member syntax then this provides it...
Solution 2
It says that you cannot use the default assignment operator. Nothing keeps you from writing your own operator=
and use a const_cast
. Unfortunately, this will be undefined behavior as v1
is declared const. So I'd suggest that you use accessors and private data.
Solution 3
You could just make it a class with everything public (thats all a struct is) and use an initialisation list - no need for getters/setters
Vektor88
Updated on February 11, 2020Comments
-
Vektor88 about 4 years
I'm having some trouble with a template struct.
template<typename T> struct A{ const int v1; T* v2; };
My purpose is to make
v1
always not editable, whilev2
should be editable if I useT
and not editable if I useconst T
as type.If I create constructor to initialize
A
, the struct becomes:template<typename T> struct A{ const int v1; T* v2; A() : v1(-1) { v2=NULL; } A(int value) : v1(value) { v2=NULL; } };
But then g++ says that I need a specific assignment operator:
error: non-static const member ‘const int A::v1’, can’t use default assignment operator
But my assignment operator should also allow editing of
v1
. The only thing I'd like to avoid is an edit from the outside, something like:A a; a.v1=10;
Is there any way to implement this (without creating getter/setter or using a pointer to a new A(int) with the desired value)?
What if I declare v1 as a const int * ? It could refer someway to some value, but it cannot edit it.
-
R. Martinho Fernandes about 12 years"without converting struct to class (...)" What you have is already a class.
-
Poodlehat about 12 yearsYou have to understand that in C++ a struct IS a class, just a very specific type of class. A struct is a class where everything is public.
-
Praetorian about 12 yearsIf the assignment operator is able to modify
const
members then you still have the problem of edit from the outside because I can just perform an assignment of the whole object instead of modifyingobj.v1
by itself -
Poodlehat about 12 yearsWhy exactly do you not want to add getter/setters, by the way?
-
Praetorian about 12 years
const mutable
would've come in very handy :-) -
Vektor88 about 12 years@Poodlehat because A has to be a struct, so I cannot use private data.
-
Vektor88 about 12 yearsWhat if I remove the constructors and declare v1 as const int*, then I could change the address v1 points to, but not the value of the pointed value.
-
Steve Jessop about 12 years@Poodlehat: "A struct is a class where everything is public". No, a struct is a class where members and bases are public by default. Structs can still have private members. It basically doesn't matter which you use of
struct
andclass
, as long as you're consistent all it affects is where you need to type access specifiers. It can also affect how the name is mangled. -
Steve Jessop about 12 years"My purpose is to make v1 always not editable" ... "my assignment operator should also allow editing of v1" -- there's your problem, directly contradicting requirements. Pick one of them to give up.
-
Vektor88 about 12 years@SteveJessop I'm thinking to declare v1 as const int* , so that I can change v1 address (and the value v1 points to), but I can't edit it.
-
Steve Jessop about 12 years@Vektor88: but then whoever it is you were trying to prevent from changing the value of
v1
when it was aconst int
, can change the pointer value now that it's aconst int *
. Plus you have the question of how theint
s are allocated and freed. There is no good way to allow the copy assignment operator to change the value, while preventing other member functions from changing it. Neither is there a good way to expose a non-const member to the public in a way that prevents them from writing it. C++ doesn't have that fine-grained encapsulation built in, you have to roll your own. -
Vektor88 about 12 years
-
-
Paul Manta about 12 yearsIs it still undefined behavior if you use
const_cast
? -
Martin Beckett about 12 years@pmr - Correct, but if it's a const I would really prefer to set it at ctor time anyway. Your solution is better for his question
-
pmr about 12 years@PaulManta The standard is quite clear here:
const_cast
results in undefined behaviour iff the object has been declaredconst
. This is the case for the member variable. I can dig up the quotes, if it makes you feel better. -
Paul Manta about 12 yearsOh, I see. Good think you put emphasis on "declared", I wouldn't have noticed it.
-
Vektor88 about 12 yearsLooks better than my solution. Thank you!