Is there a way to have an open member that is not modifiable from outside the classroom without the wrapper function of accessories?

As far as I know, this seems impossible in a simple way. Creating a const member makes it const for everyone. I would like to have a read-only property, but I would like to avoid the typical "getter". I would like const public, mutable private. Is this possible in C ++? Currently, all I can think of is some tricks with templates and friend . I am studying it now.

It may seem like a silly question, but I used to be surprised at the answers.

+6
source share
4 answers

A possible solution can be based on the inner class, the outer one is different, like the following:

 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; sf(); return i, 0; } 

As shown in the example, the class S can change the property from its member functions (see S::f ). On the other hand, a property cannot be changed in any other way, but is still read using this operator, which returns a const reference to the actual variable.

+3
source

There seems to be another, more obvious solution: use an open reference element const, pointing to a private, mutable element. real-time code is 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 sf(); 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; } 
+3
source

I like @skypjack's answer, but would write it something 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"; sf(); std::cout << s.val() << "\n"; return 0; } 

Some enable_if missing to really be common to the kernel, but the spirit should make it reusable and save calls that look like getters.

This is really a hoax with friend .

0
source

You can use a curiously repeating template pattern and add a superclass from the property class as follows:

 #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 } 
-one
source

Source: https://habr.com/ru/post/1015085/


All Articles