title: why not allow common subexpression elimination on const nonvolatile member functions?
body: <p>One of the goals of C++ is to allow user-defined types to behave as nicely as built-in types. One place where this seems to fail is in compiler optimization. If we assume that a const nonvolatile member function is the moral equivalent of a read (for a user-defined type), then why not allow a compiler to eliminate repeated calls to such a function? For example</p>
  
  <pre><code>class C {
  ...
  public:
      int get() const;
  }
  
  int main() {
      C c;
      int x{c.get()};
      x = c.get(); // why not allow the compiler to eliminate this call
  }
  </code></pre>
  
  <p>The argument for allowing this is the same as the argument for copy elision: while it changes the operational semantics, it should work for code that follows good semantic practice, and provides substantial improvement in efficiency/modularity. (In this example it is obviously silly, but it becomes quite valuable in, say, eliminating redundant iterative safety checks when functions are inlined.)</p>
  
  <p>Of course it wouldn't make sense to allow this for functions that return non-const references, only for functions that return values or const references.</p>
  
  <p>My question is whether there is a fundamental technical argument against this that doesn't equally apply to copy elision.</p>
  
  <p>Note: just to be clear, I am not suggesting the compiler look inside of the definition of get(). I'm saying that the declaration of get() by itself should allow the compiler to elide the extra call. I'm not claiming that it preserves the as-if rule; I'm claiming that, just as in copy elision, this is a case where we want to allow the compiler to violate the as-if rule. If you are writing code where you want a side effect to be semantically visible, and don't want redundant calls to be eliminated, you shouldn't declare your method as const.</p>