What Does an Ampersand After This Assignment Operator Mean

What does an ampersand after this assignment operator mean?

It's part of a feature allowing C++11 non-static member functions to differentiate between whether they are being called on an lvalues or rvalues.

In the above case, the copy assignment operator being defaulted here can only be called on lvalues. This uses the rules for lvalue and rvalue reference bindings that are well established; this just establishes them for this.

In the above case, the copy assignment operator is defaulted only if the object being copied into can bind to a non-const lvalue reference. So this is fine:

C c{};
c = C{};

This is not:

C{} = c;

The temporary here cannot bind to an lvalue reference, and thus the copy assignment operator cannot be called. And since this declaration will prevent the creation of the usual copy assignment operator, this syntax effectively prevents copy-assignment (or move-assignment) to temporaries. In order to restore that, you would need to add a && version:

C& operator=(const C&) && = default;
C& operator=(C&&) && = default;

We use ampersand during user input but Why we don't need this during assignment in C?

The scanf function has to access the object into which a value is being read. All C function arguments are passed by value, so if you wrote

int a, b;
scanf("%d%d", a, b); // THIS IS WRONG

the scanf function would only be able to see the values of a and b as they were when the function was called. It would have no way to modify a.

Assignment requires an lvalue as its left operand. An lvalue (to simplify slightly) is an expression that designates an object; the name of a variable is the most common kind of lvalue. Since the assignment operator = is built into the language, it can have special rules that apply to it. In particular, the lvalue on the LHS of the = identifies the object being assigned to; it doesn't yield the (previous) value of that object. That's how assignment is defined by the language.

For example, if you write:

a = b;

both a and b are lvalues, but they're treated differently because of their context. a refers to the object whose name is a. b also refers to an object, but in that context it yields the current value of that object.

If assignment were implemented as a function call, it would have to take the address of the object being assigned to:

int assign(int *lhs, int rhs);
assign(&a, b);

The language could have required an address for the LHS of an assignment, but allowing just the name of the target object is much more convenient.

(To explain the simplification above, the current standard's definition of lvalue is "an expression (with an object type other than void) that potentially designates an object". The word "potentially" is there because, for example, *ptr where ptr is a pointer is an lvalue even if the current value of ptr is NULL. Being an lvalue is a compile-time concept. Attempting to assign a value to *ptr is legal, but has undefined behavior.)

What does ampersand mean in function call?

Yes, you are right: the ampersand takes the address of an lvalue (a variable) and passes it as pointer.

Your adjust() function would look like:

void adjust(double *a, double f) {
... do a lot of stuff
*a = *a * f/2+1.0; // dummy formula that will change the content
...
};

So in the function you'd use *a every time you'd want to use the value pointed at by the first argument, and everytim you want to assign a new value to the original variable.

C++ - What does it mean when you put an ampersand (&) in front of an rvalue reference?

It's simply checking for self-assignment. If the address of the object being passed in is the same as this then do nothing.

What does the single ampersand after the parameter list of a member function declaration mean?

It means the member will be invoked when the object is an lvalue reference.

[C++11: 9.3.1/5]: A non-static member function may be declared with a ref-qualifier (8.3.5); see 13.3.1.

[C++11: 13.3.1/4]: For non-static member functions, the type of the implicit object parameter is

  • “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier
  • “rvalue reference to cv X” for functions declared with the && ref-qualifier

where X is the class of which the function is a member and cv is the cv-qualification on the member function declaration. [..]

(and some more rules that I can't find)

Without a ref-qualifier, the function can always be invoked, regardless of the value category of the expression through which you're invoking it:

struct foo
{
void bar() {}
void bar1() & {}
void bar2() && {}
};

int main()
{
foo().bar(); // (always fine)
foo().bar1(); // doesn't compile because bar1() requires an lvalue
foo().bar2();

foo f;
f.bar(); // (always fine)
f.bar1();
f.bar2(); // doesn't compile because bar2() requires an rvalue
}

Live demo (thanks Praetorian)

What does the & (ampersand) at the end of member function signature mean?

Ref-qualifiers - introduced in C++11

Ref-qualifiers is not C++17 feature (looking at the tag of the question), but was a feature introduced in C++11.

struct Foo
{
void bar() const & { std::cout << "const lvalue Foo\n"; }
void bar() & { std::cout << "lvalue Foo\n"; }
void bar() const && { std::cout << "const rvalue Foo\n"; }
void bar() && { std::cout << "rvalue Foo\n"; }
};

const Foo&& getFoo() { return std::move(Foo()); }

int main()
{
const Foo c_foo;
Foo foo;

c_foo.bar(); // const lvalue Foo
foo.bar(); // lvalue Foo
getFoo().bar(); // [prvalue] const rvalue Foo
Foo().bar(); // [prvalue] rvalue Foo

// xvalues bind to rvalue references, and overload resolution
// favours selecting the rvalue ref-qualifier overloads.
std::move(c_foo).bar(); // [xvalue] const rvalue Foo
std::move(foo).bar(); // [xvalue] rvalue Foo
}

Note that an rvalue may be used to initialize a const lvalue reference (and in so expanding the lifetime of the object identified by the rvalue), meaning that if we remove the rvalue ref-qualifier overloads from the example above, then the rvalue value categories in the example will all favour the remaining const & overload:

struct Foo
{
void bar() const & { std::cout << "const lvalue Foo\n"; }
void bar() & { std::cout << "lvalue Foo\n"; }
};

const Foo&& getFoo() { return std::move(Foo()); }

int main()
{
const Foo c_foo;
Foo foo;

// For all rvalue value categories overload resolution
// now selects the 'const &' overload, as an rvalue may
// be used to initialize a const lvalue reference.
c_foo.bar(); // const lvalue Foo
foo.bar(); // lvalue Foo
getFoo().bar(); // const lvalue Foo
Foo().bar(); // const lvalue Foo
std::move(c_foo).bar(); // const lvalue Foo
std::move(foo).bar(); // const lvalue Foo
}

See e.g. the following blog post for for a brief introduction:

  • Andrzej's C++ blog - Ref-qualifiers

rvalues cannot invoke non-const & overloads

To possibly explain the intent of your recollected quote from the CppCon talk,

"... that the only true way of overloading operator= ..."

we visit [over.match.funcs]/1, /4 & /5 [emphasis mine]:

/1 The subclauses of [over.match.funcs] describe the set of candidate functions and the argument list submitted to overload
resolution in each context in which overload resolution is used. ...

/4 For non-static member functions, the type of the implicit object parameter is

  • (4.1) — “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier

  • (4.2) — “rvalue reference to cv X” for functions declared with the && ref-qualifier


where X is the class of which the function is a member and cv is the
cv-qualification on the member function declaration. ...

/5 ... For non-static member functions declared without a ref-qualifier, an additional rule applies:

  • (5.1) — even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as
    in all other respects the argument can be converted to the type of the
    implicit object parameter.
    [ Note: The fact that such an argument is
    an rvalue does not affect the ranking of implicit conversion
    sequences. — end note ]

From /5 above, the following overload (where the explicit & ref-qualifier has been omitted)

struct test
{
test& operator=(const test&) { return *this }
}

allows assigning values to r-values, e.g.

int main()
{
test t1;
t1 = test(); // assign to l-value
test() = t1; // assign to r-value
}

However, if we explicitly declare the overload with the & ref-qualifier, [over.match.funcs]/5.1 does not apply, and as long we do not supply an overload declared with the && ref-qualifier, r-value assignment will not be allowed.

struct test
{
test& operator=(const test&) & { return *this; }
};

int main()
{
test t1;
t1 = test(); // assign to l-value
test() = t1; // error [clang]: error: no viable overloaded '='
}

I won't place any opinion as to whether explicitly including the & ref-qualifier when declaring custom assignment operator overloads is "the only true way of overload operator=", but would I dare to speculate, then I would guess that the intent behind such a statement is the exclusion of to-r-value assignment.

As a properly designed assignment operator should arguably never be const (const T& operator=(const T&) const & would not make much sense), and as an rvalue may not be used to initialize a non-const lvalue reference, a set of overloads for operator= for a given type T that contain only T& operator=(const T&) & will never proviade a viable overload that can be invoked from a T object identified to be of an rvalue value category.

how does the ampersand(&) sign work in c++?

To start, note that

this

is a special pointer ( == memory address) to the class its in.
First, an object is instantiated:

CDummy a;

Next, a pointer is instantiated:

CDummy *b;

Next, the memory address of a is assigned to the pointer b:

b = &a;

Next, the method CDummy::isitme(CDummy ¶m) is called:

b->isitme(a);

A test is evaluated inside this method:

if (¶m == this) // do something

Here's the tricky part. param is an object of type CDummy, but ¶m is the memory address of param. So the memory address of param is tested against another memory address called "this". If you copy the memory address of the object this method is called from into the argument of this method, this will result in true.

This kind of evaluation is usually done when overloading the copy constructor

MyClass& MyClass::operator=(const MyClass &other) {
// if a programmer tries to copy the same object into itself, protect
// from this behavior via this route
if (&other == this) return *this;
else {
// otherwise truly copy other into this
}
}

Also note the usage of *this, where this is being dereferenced. That is, instead of returning the memory address, return the object located at that memory address.

What does an ampersand mean when assigning a variable? (Java)

It's the bitwise AND operator.

It operates on each bit position independently; the output bit in position n is only 1 if both the corresponding input bits in position n are also 1.

In this context, the 0x7f7f7f is being used as a bit-mask. By having certain bit positions as 0, it means that the corresponding bit positions in clothes will always be 0. All other bit positions will take on the same value as produced by random.nextInt(0x1000000).

Pointers in C: when to use the ampersand and the asterisk?

You have pointers and values:

int* p; // variable p is pointer to integer type
int i; // integer value

You turn a pointer into a value with *:

int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to

You turn a value into a pointer with &:

int* p2 = &i; // pointer p2 will point to the address of integer i

Edit:
In the case of arrays, they are treated very much like pointers. If you think of them as pointers, you'll be using * to get at the values inside of them as explained above, but there is also another, more common way using the [] operator:

int a[2];  // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element

To get the second element:

int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element

So the [] indexing operator is a special form of the * operator, and it works like this:

a[i] == *(a + i);  // these two statements are the same thing


Related Topics



Leave a reply



Submit