2

What does the standard say about copy/assignment of fundamental types?

For class types, we have copy constructor, assignment operator, which takes the right hand side as a reference (it must be a reference, otherwise we had infinite recursion):

struct Foo {
    Foo(const Foo &);
};

How does this defined for fundamental types?

Look at this example:

const Foo foo;
Foo f = foo;

const int a = 2;
int b = a;

Here, f = foo; odr-uses foo, as copy-constructor takes a reference, right?. If copy of fundamental types had a reference parameter, then b = a would odr-use a as well. Is it the case? If not, how is it handled?

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
geza
  • 28,403
  • 6
  • 61
  • 135
  • For fundamental types, the implementation (aka compiler) maps the statement `b = a` to a set of machine instructions that copies the value of `a` into `b` if they are of the same type. There is no actual constructor that is required to be called. So the implementation is free to do that as it likes. Class construction (emitting code to actually call the constructor appropriately) is actually the special case, not handling of fundamental types. – Peter Nov 22 '18 at 11:02
  • @Peter: of course. But this doesn't answer the question whether `a` is odr-used or not. – geza Nov 22 '18 at 11:06
  • i guess the downvotes are due to not understanding what the `language-lawyer` tag is for, otherwise it would be interesting to know what the downvotes are for – 463035818_is_not_an_ai Nov 22 '18 at 11:11
  • 1
    The title should be "does assignment of an int odr-use the source" or similar, since that seems to be the question. Also the class example seems irrelevant – M.M Nov 22 '18 at 11:11
  • @M.M: that was the originating problem why I asked this. But then I tried to find what does the standard say about copy/assignment of fundamental types, and I haven't found it. So actually, I'm interested in copy/assignment of fundamental types, not odr-usage (I found odr-usage already, it was easy to find. But I looked through basic.fundamental several times, and haven't found anything - no wonder, as the information is somewhere else). – geza Nov 22 '18 at 11:14
  • @user463035818: I've stopped worrying about downvotes a long time ago. The point is, that we got a good answer, and we (others and me) learned something new. 99% of the time, people don't say the reason of the downvote. So it is pretty useless. – geza Nov 22 '18 at 11:26
  • @geza yep. I was just curious what could be a reason, because honestly my standardese is soo low that I dont really understand the question ;). Anyhow if you did care about votes, downvotes you get within the first minutes while upvotes are collected on the long run – 463035818_is_not_an_ai Nov 22 '18 at 11:29
  • there's not any deeper mystery or info about primitive types... copy one and it gets copied – M.M Nov 22 '18 at 11:39
  • @M.M: yes, we all know this by experience. I just didn't find the section of the standard which exactly specifies this. For classes, we know about copy constructor, it's common knowledge, easy to find in the standard. I had troubles to find the same info for fundamental types. I did a search for "copy", read the whole basic.fundamental section, but the answer didn't show up. The correct term to search for would have been "initialization". – geza Nov 22 '18 at 11:45
  • or "assignment" – M.M Nov 22 '18 at 11:58
  • Operations on fundamental types aren't treated as overloaded or templated operators. And they couldn't be, the rules are specific, convoluted, and awful. (Who can recite the rules for integer promotions?) – curiousguy Nov 23 '18 at 05:12

1 Answers1

6

We can trace it. Starting at [dcl.init].

(17.8) - Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. Standard conversions will be used, if necessary, to convert the initializer expression to the cv-unqualified version of the destination type; no user-defined conversions are considered. If the conversion cannot be done, the initialization is ill-formed. When initializing a bit-field with a value that it cannot represent, the resulting value of the bit-field is implementation-defined.

The standard conversion in this case would be the lvalue-to-rvalue conversion on a. But that doesn't odr-use a. For we see in [basic.def.odr]

2 A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion is applied to e, or e is a discarded-value expression.

a is a constant expression and substitution of a for x and ex above demonstrates it holds the other half of the condition, so it's not odr-used.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    @YSC - `a` is a constant expression. – StoryTeller - Unslander Monica Nov 22 '18 at 11:05
  • As for `[dcl.init]`, the OP asked to for an explanation of how this initialization works. So it made sense to me to start there. – StoryTeller - Unslander Monica Nov 22 '18 at 11:06
  • @StoryTeller I overlooked the rule... but... does it mean I can define a `const int a` with different values in different translation units? I know they would have internal linkage, but stilll I'm surprised. – YSC Nov 22 '18 at 11:08
  • @YSC - You can. It's what makes it usable as an (superior) alternative to macros for constants. – StoryTeller - Unslander Monica Nov 22 '18 at 11:09
  • Thanks for the answer, dcl.init was the missing piece I was looking for. But it is just about initialization, isn't it? What about assignment? Or is assignment covered by this section as well? – geza Nov 22 '18 at 11:38
  • @geza - Assignment is an expression, so it's covered in [expr.ass]. You can see similar wording about conversions in [¶ 3](https://timsong-cpp.github.io/cppwp/n4659/expr.ass#3). Which takes us back to the l-to-r conversion again. – StoryTeller - Unslander Monica Nov 22 '18 at 11:43
  • @StoryTeller If we take an aggregate with only fundamental types in it and do not declare/define any special member functions (so the type is trivial), does it still stand that the l value to r value conversion does not introduce odr useage? – phön Nov 22 '18 at 12:36
  • 1
    @phön - Such an object would be a constant expression too, so [an l-to-r conversion alone won't odr-use it](http://coliru.stacked-crooked.com/a/972c6a2bbfd6512e), I think. – StoryTeller - Unslander Monica Nov 22 '18 at 12:45
  • @StoryTeller Ehm i dont know if this is the right wording, but does a return by value of such a trivial type lead to odr usage? (asking because of this https://stackoverflow.com/questions/53407371/undefined-reference-to-class-static-constexpr-struct-g-vs-clang ) – phön Nov 22 '18 at 12:58
  • @StoryTeller Thanks for your insights! – phön Nov 22 '18 at 13:21