Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why a different type variable can be used as an argument of a parameter of const reference parameter in C++

void foo(const int& v) {
    int x = v;
    std::cout << x;
}

int main()
{
    unsigned y = 1;
    foo(y);
}

Is passing y in place of a const int& legal in C++

like image 444
xiaofeng z Avatar asked Feb 06 '18 16:02

xiaofeng z


People also ask

Why should we use const references for function parameters rather than pass by value?

Passing a parameter by const reference should be chosen where the semantics of references are actually required, or as a performance improvement only if the cost of potential aliasing would be outweighed by the expense of copying the parameter. At times, copying your parameters can also give you locality benefits.

What's a benefit of declaring the parameter as a const reference instead of declaring it as a regular object?

What is one benefit of declaring the parameter as a const reference instead of declaring it as a regular object? Actually, objects cannot be passed as regular variables, because they require a constructor call. Therefore, a const reference is the only way to pass class instances to functions.

What is the benefit of declaring the parameter as a const reference?

The important difference is that when passing by const reference, no new object is created. In the function body, the parameter is effectively an alias for the object passed in. Because the reference is a const reference the function body cannot directly change the value of that object.

Why are const reference parameters useful in C++?

Passing by const reference offers the same primary benefit as pass by reference (avoiding making a copy of the argument), while also guaranteeing that the function can not change the value being referenced.


2 Answers

There are two factors that allow your code to work. First, function arguments are allowed up to one implicit conversion if it would allow them to match an overload. Second, const references can bind to temporaries. What is happening here is y is implicitly converted to int, creating a temporary copy. v is then bound to that temporary.

Consider the following example :

#include <iostream>

void foo(const unsigned int & v) {
    std::cout << &v << '\n';
}

void bar(const int & v) {
    std::cout << &v << '\n';
}

int main()
{
    unsigned int y = 1;
    std::cout << &y << '\n';
    foo(y);
    bar(y);
    return 0;
}

You will find that foo(y) prints the same address as y where as bar(y) prints a different address. This won't work with non-const references. Notably, if you could, it would mean that changing v might not actually change y.

like image 152
François Andrieux Avatar answered Sep 17 '22 08:09

François Andrieux


Yes, this this can be quite annoying. Compilation passes due to an implicit conversion of y to an anonymous temporary int at the calling site, and a const int& binding is allowed.

You can defeat this by writing

void foo(unsigned v) = delete;

or even

template<typename Y> void foo(Y v) = delete;

so all overloads other than the one you have explicitly given are deleted.

like image 31
Bathsheba Avatar answered Sep 19 '22 08:09

Bathsheba