2

I'm trying to figure out how C++ actually breaks down the argument-passing when the formal argument is a reference and the actual argument is of a type that requires type-conversion.

  • Here's an example. Are the calls to f(10) and g(5) supposed to compile/run or they supposed to throw an error?

f(10) passes an int but the formal-argument is a reference to const. So the compiler has to bind the reference to 10. How does it do that? What assignment statement does it create to bind it? would it create a temporary object (say tmp) and insert a statement like A tmp(10); f(tmp); instead of call to f(10)?

class A {
public:
    A(int);
    ~A() = default;
};

void f(const A&);
void g(A&);

f(10);
g(5);
  • Can someone elaborate on what type-conversion and argument-passing rules apply here?

  • When running g(5) call I get the error:

    error: cannot bind non-const lvalue reference of type ‘A&’ to an rvalue of type ‘A’

    Can someone explain the reasoning behind this?

13
  • 1
    The compiler is allowed to make a single implicit conversion to make arguments match, so since a A can be constructed from a int it can make the call to f(10) by converting the integer to an instance of A and then pass that temporary A by const reference to the function. Calling g(5) doesn't work since you can't pass a temporary A by non-const reference. Commented Mar 27 at 0:43
  • 2
    @JoeBlack How the compiler materializes the temporary A and pass it to the function is an implementation detail of the compiler. Commented Mar 27 at 0:49
  • 1
    It's very similar to converting the call f(10) to f(A{10}). It's not quite the same, since the latter could do an implicit conversion from A to something else, but it's close enough. Commented Mar 27 at 0:56
  • 1
    @JoeBlack It simply binds the reference to the temporary object. That has no other observable side-effects. Statements are C++ source code level constructs. They're instructions to the compiler that describe the behavior of the program you want it to write. The compiler doesn't implement behavior via C++ statements (aside from a very few places where the standard describes behavior of one source construct in terms of another; but even then it just mandates that they have the same behavior). Commented Mar 27 at 1:32
  • 1
    Just to be clear, do you understand how reference binding works in a functin parameter in the simpler case (calling f(const A&) and pass a A(5) to it)? Why do you keep talking about the non-existent and unrelated "assignment" or "statement"? The "reference initialization" page on cppreference may help. Also for C++17 and later, read about temporary materialization. Commented Mar 27 at 3:10

1 Answer 1

2

f(10) passes an int but the formal-argument is a reference to const. So the compiler has to bind the reference to 10. How does it do that? What assignment statement does it create to bind it?

It can't bind to 10 directly. It can bind only to a valid A object.

would it create a temporary object (say tmp) and insert a statement like A tmp(10); f(tmp); instead of call to f(10)?

Essentially, yes. A const reference can bind to a temporary, so that is exactly what the compiler does - it implicitly creates an unnamed temporary A object, constructed using 10 as input to its constructor, then passes a reference to that object into f(), and then destroys that object after the full statement that created it is finished (ie in your example, when the ; is reached).

When running g(5) call I get the error error: cannot bind non-const lvalue reference of type ‘A&’ to an rvalue of type ‘A’. Can someone explain the reasoning behind this?

It is because a non-const reference is not allowed to bind to a temporary, so you will have to create a non-temporary A object yourself and then pass it to g() explicitly.

Sign up to request clarification or add additional context in comments.

4 Comments

my question is exactly how is the actual argument (A(10) in this case) is bound to the formal-argument (const A& a here)? Is that done through an assignment statement? or some other statement?
@JoeBlack There is no assignment. A reference is just an alias, ie another name, for an existing object. Like JesperJuhl told you, HOW the compiler implements the reference parameter passing is implementation-defined, but commonly it is just a pointer to the object at the machine level, though it is not a pointer at the language level. If you want to know the details for YOUR particular compiler, then look at the machine code it generates.
@JoeBlack A temporary A is constructed, viz A(10). A reference to that temporary has type const A &, and that is passed. A reference is a property of the temporary object itself and the implementation (e.g. compiler) knows how to obtain a reference to an object, so there is no further assignment or construction involved in obtaining the reference from the temporary. Practically, a reference is just a handle, and compilers often pass the address of the object behind the scenes, but the standard doesn't mandate/require that.
@Peter "A reference is a property of the temporary object itself" - what???

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.