5

This is based on the original question that was asked here.

[Detailed]: Here is the relevant question as requested in comments

Lippman's c++ primer on p.303 mentions:

class Account {
private:
  static constexpr int period = 30;
  double daily_tbl[period];
}

If the member is used only in contexts where the compiler can substitute the member's value, then an initialized const or constexpr static need not be separately defined. However, if we use the member in a context in which the value cannot be substituted, then there must be a definition for that member.

Also:

For example, if we pass Account::period to a function that takes a const int&, then period must be defined.

So why does passing Account::period to a function that takes a const int&, needs that period must be defined?
It will be very helpful to know,

  • What is the rationale?
  • Does the standard explicitly specify these scenarios or these are deduced from a more generic quotation?
Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 2
    Please make your question self-contained. File it down to a minimal example if you can. – Kerrek SB Jan 27 '13 at 13:38
  • @KerrekSB: The link is to an SO question(no external link) & I don't expect it to vanish, it is neither a duplicate nor a candidate for one. I link to the question because the context is important for the question i ask. – Alok Save Jan 27 '13 at 13:39
  • 2
    But I don't want to play wild-link-chase in order to synthesize a question. And how would I make reference to parts of the question in my answer? "See line 3 in answer 2 of the linked question"? It's just too awkward. If you care about the question, put a bit of effort in. – Kerrek SB Jan 27 '13 at 13:41
  • +1. The referenced question puzzled me as well. So if anyone has an answer to *this* question, he might also have one to this [related yet distinct one](http://stackoverflow.com/questions/14547986/what-am-i-allowed-to-do-with-a-static-constexpr-in-class-initialized-data-memb#comment20293462_14547986). In that case, please shed some light. I would very much appreciate it. – Andy Prowl Jan 27 '13 at 13:58
  • This is relaxed requirements compared to the C++03 standard, where technically the constant would *always* have to be defined. Not that any compilers enforced that. The new wording is just codifying existing practice. – Bo Persson Jan 27 '13 at 17:59

2 Answers2

7

If the member never has it's address taken (or, equivalently, a reference bound to it), the compiler can simply use it's value, and this value is the same in every TU, so there's no problem because rvalues don't have to have addresses. Or it can make a copy in each TU or whatever it wants, because you can't observe it's address.

But if you attempt to take the address, the compiler has an obligation to make sure that in all TUs, the address is the same. Because of C++'s truly horrendous TU system, this means needing one, and only one, explicit definition.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • *This* is a useful answer. +1 – Andy Prowl Jan 27 '13 at 14:11
  • I understand taking address of an member needs it to be placed in the memory and if I remember correctly Bjarne himself has a quote relevant to the effect, but Why does binding a reference to the object need it to be placed in memory? – Alok Save Jan 27 '13 at 14:13
  • They are, fundamentally, the same operation. – Puppy Jan 27 '13 at 14:14
  • Essentially yes, I agree but also the standard doesn't say so? So how can something that standard doesn't say be a rationale for something that the standard does say and explicitly so? – Alok Save Jan 27 '13 at 14:15
  • No idea, I never checked, but I doubt that it does not reflect this fact. Remember that if you bind a reference to `period`, the compiler would have to prove that you never, ever, took `period`'s address in order for not using a definition to work- and that's impossible in the general case. In Standardese, it is odr-used if lvalue-to-rvalue conversion does not apply, and that does not apply when a reference is bound, because you bind a reference to `period`, not "The value of `period` as it is right now.". – Puppy Jan 27 '13 at 14:17
  • @alok the standard doesnt mention rationales. so almost every description of rationale is not found in the standard. – Johannes Schaub - litb Jan 27 '13 at 14:22
  • 1
    The way I understand it (which I assume to be wrong at this point), a static `constexpr` variable is *effectively* a value. It can't change, it's global, and it's determined at compile-time. What does distinguish it conceptually from (say) the integer literal "4"? And you can bind 4 to a `const` lvalue reference – Andy Prowl Jan 27 '13 at 14:37
  • Because it's not a value. It's an object- an lvalue, or to be more accurate, the compiler has to treat it as one, if you perform operations on it that require it to be that way. 4 does not have to have the same address every time. `period` does. – Puppy Jan 27 '13 at 14:38
  • For anyone who wants to google what TU is, it is Translation Unit. Roughly, a translation unit means a file. – aafulei Dec 14 '21 at 14:32
0

I would imagine the rationale to be something along the lines of:

const int* get_addr(const int& i) {
  return &i;
}

class Account {
private:
  static constexpr int period = 30;
  double daily_tbl[period];

  const int* period_ptr() {
    return get_addr(period);
  }
}
sheu
  • 5,653
  • 17
  • 32
  • This adds an additional condition of address of the static member being taken. The quote in the book merely states *"if we pass `Account::period` to a function that takes a `const int&`, then `period` must be defined."* So this does not match the condition stated in book. – Alok Save Jan 27 '13 at 13:57
  • As to the now-disappeared comment about doing this to literals: the compiler creates a temporary object in that case. It cannot for `constexpr` objects, since they're explicitly named. See: http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ – sheu Jan 27 '13 at 14:14