Hi all,

if we have to add a new keyword (i.e. constpub) to make something like this special case to work, I would suggest to add a keyword "property" to allow special functions to be called using its name as variable for assignment syntax.

//a.hpp
class A
{
public:
  //read/write properties, have additional protection than using "value" directly
  property int v() { return value; }                          //read property
  property int v(int val) { value=val; return value; }        //write property, return type and param type don't need to match
  property int v(short val) { value=val; return value; }      //write property, overload allowed, as long as it doesn't conflict with others

  //read only property, no write property defined
  property int& v_readonly() { return value_readonly; }       //can return reference to variable

  //write only property, no read property defined
  property void v_writeonly(int val) { value_writeonly=val; } //return type can be void

  //static read only property, static
  property static int v_static() { return value_static; }

protected:
  //protected property for use by inherited class
  property int v_protected() { return value_protected; }             //read property
  property void v_protected(const int& val) { value_protected=val; } //write property, return type can be void

private:
  int value;
  int value_readonly;
  int value_writeonly;
  int value_protected;
  static int value_static;
}

//main.cpp
#include "a.hpp"
int main()
{
  int v=5;
  A a{};
  a.v=v+1;        //ok
  v=a.v;          //ok
 
  v=a.v_readonly; //ok
  a.v_readonly=v; //error, not defined

  a.v_writeonly=v; //ok;
  v=a.v_writeonly; //error, not defined

  v=a.v_static;    //ok
  a.v_static=v;    //error, not defined

  a.v_protected=v; //error, protected for inherited class
  v=a.v_protected; //error, protected for inherited class
}

though it still use private variable, but property is more useful than bare "constpub" variable.

Thanks,

Jianping

On 1/10/2020 08:46 PM, Jorg Brown via Std-Proposals wrote:
On Thu, Nov 21, 2019 at 2:34 AM Andrew Tomazos via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Please find attached a 2-page draft proposal entitled:

     Proposal of constpub

It seems a little thing but easy to implement and I think it may have broad appeal.

Anyway, initial thoughts appreciated.
    -Andrew.

Interesting...

From the paper:

For example:

struct S {
  constpub int i;
  void f() {
    std::cout << i; // OK: private read
    i = 42; // OK: private write
  }
};

int main() {
  S s;
  std::cout << s.i; // OK: public read
  s.i = 42; // ERROR: public write
}

This is an extremely common thing to want to do.

You've stated correctly in the paper that the common way to handle this is to provide a public read-only accessor function.

There's another way to handle it, though: you could use a constexpr reference:

struct S {
  constexpr const int& i = private_i;
  void f() {
    std::cout << private_i << '\n'; // OK: private read
    private_i = 42; // OK: private write
  }

 private:
  int private_i;
};

int main() {
  S s{};
  s.f();
  std::cout << s.i << '\n'; // OK: public read
  s.i = 42; // ERROR: public write
  s.private_i = 42; // ERROR: public access to private var
}

Obligatory godbolt reference:  https://godbolt.org/z/7ieE4h 

Now, there's three problems with this:

1) The standard does not allow non-static data members to be declared constexpr.
2) If you remove the constexpr, this all works but the reference now consumes memory in the struct.
3) If the struct is copied, the reference is also copied, and so the reference now refers to the original struct.

But (1) Isn't just bad news: it's also good news.  It means that in a future C++, we could allow programmers to declare a constexpr member that was a reference, that satisfied our needs: always referring to what it said it referred to, no matter if a copy happened or not, and it would be backwards-compatible with existing code.

It doesn't 100% satisfy what you're looking for, since the private member and the public member would have different names, but I assume that would be OK with you.

Regarding "this is an extremely common thing to want to do", that's absolutely true for me, because we often want to migrating existing code.  For example, we might want an associative container whose elements have two members: "key" and "value".  But for compatibility, we might also want to refer to them as "first" and "second".

And on a related note, while I might want my container code to be able to access "key' and "value" in a mutable way, I might want my users to have read/write access to "value", but be limited to read-only access to "key".

-- Jorg