Is Pass-by-Reference part of a Function Signature?

  • Thread starter MinusTheBear
  • Start date
  • Tags
    Function
In summary: This is correct. The first and third functions have differing signatures, namely sum(int,int) and sum(int&,int&).
  • #1
MinusTheBear
22
0
Hey all,

I'm reviewing for a data structures exam and covering stuff from the previous course. I am a little confused about something between the book and what my professor says.

If I have the following prototypes:
int sum(int a, int b);
void sum(int a, int b);
int sum(int&a, int&b);

So, I know this will create a compilation error because the compiler won't be able to disambiguate between the signatures. However, I want to be sure I understand something. The first two functions have the same signature, while the third one has a different signature since it is pass-by-reference, correct? However, in the case of the third function, even though it's a different signature, the compiler won't be able to disambiguate the function calls so it'll cause a compilation error even if we were to remove one of the first two functions.

Is all of that correct?
 
Technology news on Phys.org
  • #2
MinusTheBear said:
Hey all,

I'm reviewing for a data structures exam and covering stuff from the previous course. I am a little confused about something between the book and what my professor says.

If I have the following prototypes:
int sum(int a, int b);
void sum(int a, int b);
int sum(int&a, int&b);

So, I know this will create a compilation error because the compiler won't be able to disambiguate between the signatures. However, I want to be sure I understand something. The first two functions have the same signature, while the third one has a different signature since it is pass-by-reference, correct? However, in the case of the third function, even though it's a different signature, the compiler won't be able to disambiguate the function calls so it'll cause a compilation error even if we were to remove one of the first two functions.

Is all of that correct?
Right. The first two functions have the same signature, because they both have the same number and types of arguments. Based on the results from my compiler (VC 2015), the first and third functions also have the same signature; namely sum(int, int). A reference to an int, say, is still an int.

If the declaration for the third function were changed to int sum(int * a, int * b);, then the first and third sum declarations would have different signatures. The two arguments would be pointers to int (i.e., addresses of int values) rather than int values.
 
  • #3
Mark44 said:
the first and third functions also have the same signature; namely sum(int, int). A reference to an int, say, is still an int.

This is not correct. The first and third functions have differing signatures, namely sum(int,int) and sum(int&,int&). See, for instance, the following program demonstrating how to call foo(int,int) without ambiguity:

#include <stdio.h>
void foo(int a, int b) { puts("first"); }
void foo(int& a, int &b) { puts("second"); }
int main()
{
int a, b;
const int x = 1;
const int y = 2;
foo(x, y); // ok!
foo(6, 4); // ok!
foo(a, 7); // ok!
// foo(a, b); // ambiguous

return 0;
}

The reason this works is because foo(int&,int&) cannot discard const qualifiers nor can it take a reference to an rvalue, so there is only one option.
 
  • #4
TheComet said:
This is not correct. The first and third functions have differing signatures, namely sum(int,int) and sum(int&,int&).
My earlier comment was based on my example using VS 2015, which considers the two sum function overloads below as having the same signature, with both being of type (int, int).

Here is from the Visual Studio documentation, in the topic titled "Function Overloading":
Overloaded functions differentiate between argument types that take different initializers. Therefore, an argument of a given type and a reference to that type are considered the same for the purposes of overloading. They are considered the same because they take the same initializers. For example, max( double, double ) is considered the same as max( double &, double & ). Declaring two such functions causes an error.

C:
int sum(int a, int b) {return a + b;}
int sum(int &a, int &b) {return a + b;}

int main(void)

{
   int a = 5, b = 10;
   int z, w;
   z = sum(3, 5);
   w = sum(a, b);
   return 0;
}

TheComet said:
The reason this works is because foo(int&,int&) cannot discard const qualifiers nor can it take a reference to an rvalue, so there is only one option.
I don't see how this can be the reason -- there aren't any const qualifiers to be discarded.
 
  • #5
If what you say were true, why does my code compile on VS2015? Why am I able to disambiguate the supposed "identical" functions? The reason is because foo(int,int) and foo(int&,int&) are distinct types.

Here is the relevant section from the current C++ ISO standard (section 16.1 Overloadable declarations)[1]:

Parameter declarations that differ only in the presence or absence of const and/or volatile are
equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when
determining which function is being declared, defined, or called. Example:
Code:
typedef const int cInt;
int f (int);
int f (const int); // redeclaration of f(int)
int f (int) { /* ... */ } // definition of f(int)
int f (cInt) { /* ... */ } // error: redefinition of f(int)

Only the const and volatile type-specifiers at the outermost level of the parameter type specification
are ignored in this fashion; const and volatile type-specifiers buried within a parameter type
specification are significant and can be used to distinguish overloaded function declarations. In
particular, for any type T, “pointer to T”, “pointer to const T”, and “pointer to volatile T” are
considered distinct parameter types, as are “reference to T”, “reference to const T”, and “reference to
volatile T”.

Note in particular the last sentence.

Mark44 said:
I don't see how this can be the reason -- there aren't any const qualifiers to be discarded.

Did you read my code? I had:
const int x = 1;
const int y = 2;

Passing const x and y makes the second foo() unfeasable, because the parameters in foo(int& a, int& b) would have to discard the const qualifiers of const int x and const int y. Therefore, the only viable overload is foo(int a, int b) and the call is unambiguous.

[1] https://github.com/cplusplus/draft/tree/master/source
 
  • #6
My compiler (Linux GCC and mingw) treats the first and last as separate signatures. In fact, it doesn't even throw a warning. If I remove the pass-by-reference, however, it will not compile saying that it has already been defined. Which is interesting, because I thought for sure that they would be treated the same. It seems the compiler gives priority to the pass-by-value function.
 
  • #7
TheComet said:
If what you say were true, why does my code compile on VS2015? Why am I able to disambiguate the supposed "identical" functions? The reason is because foo(int,int) and foo(int&,int&) are distinct types.
I can get the following code to run -- it's similar to yours in that the actual arguments (as opposed to the formal parameters of the second sum() function) are declared as const int.

C:
int sum(int a, int b) {return a + b;}
int sum(int &a, int &b) {return a + b;}

int main(void)

{
   const int a = 5, b = 10;
   int z, w;
   z = sum(3, 5);
   w = sum(a, b);
   return 0;
}

TheComet said:
Here is the relevant section from the current C++ ISO standard (section 16.1 Overloadable declarations)[1]:

Note in particular the last sentence.
Here's the last sentence:
In particular, for any type T, “pointer to T”, “pointer to const T”, and “pointer to volatile T” are
considered distinct parameter types, as are “reference to T”, “reference to const T”, and “reference to
volatile T”.
I interpret this to say that "pointer to T", "pointer to const T", and "pointer to volatile T" are distinct parameter types, and that the last two are a different group of distinct parameter types. I don't interpret this to mean that, for example, int and int& are distinct parameter types.
TheComet said:
Did you read my code? I had:
const int x = 1;
const int y = 2;
Yes, I read your code, but we're talking about function signatures, and "const" was nowhere in either sum() version's list of parameters. Removing "const" from the declarations of x and y in your code causes compilation to fail, as in the following example (the only difference between this code and the code above is the main() body). Also, using variables instead of literals causes a compiler error, "ambiguous call to overloaded function".
C:
const int a = 5, b = 10;
int c = 3, d = 5;
int z, w;
z = sum(a, b);
w = sum(c, d);

TheComet said:
Passing const x and y makes the second foo() unfeasable, because the parameters in foo(int& a, int& b) would have to discard the const qualifiers of const int x and const int y. Therefore, the only viable overload is foo(int a, int b) and the call is unambiguous.

[1] https://github.com/cplusplus/draft/tree/master/source
 
  • #8
You're missing the entire point of what I'm trying to say.

Of course removing const from my example causes it to fail. In your first post you said:
Mark44 said:
the first and third functions also have the same signature; namely sum(int, int). A reference to an int, say, is still an int.

I was proving this statement false by demonstrating a program where the overloads sum(int,int) and sum(int&,int&) can be resolved unambiguously, which means that sum(int,int) and sum(int&,int&) must contain distinct parameter types. You seem to still think that they are not distinct types for some reason, even after quoting the standard and demonstrating a working program that goes against what you claim.

Mark44 said:
I don't interpret this to mean that, for example, int and int& are distinct parameter types.

int and int& are literally distinct parameter types. I don't know what else to say to you...
 
  • #9
@TheComet, I think we're arguing different things. Before coming across this thread, I would have thought that sum(int, int) and sum(int &, int&) would represent different signatures, since they are obviously literally different. However, my compiler (and yours) treats them, for the purpose of overloading, as being the same.
Again, from the VS 2015 documentation, under "Function Overloading" in the subtopic "Argument Type Differences":
Overloaded functions differentiate between argument types that take different initializers. Therefore, an argument of a given type and a reference to that type are considered the same for the purposes of overloading. They are considered the same because they take the same initializers. For example, max( double, double ) is considered the same as max( double &, double & ). Declaring two such functions causes an error.

For the same reason, function arguments of a type modified by const or volatile are not treated differently than the base type for the purposes of overloading.

However, the function overloading mechanism can distinguish between references that are qualified by const and volatile and references to the base type.

The business about const and volatile in your example doesn't help to clarify things, IMO. An example that would help dispel the mists here is the following.
C:
int sum(int &a, int &b){ return a + b;}
int sum(const int &a, const int &b){ return a + b;}

int main(void)

{
   int a = 5, b = 10;
   const int c = 8, d = 7;
   int z;

   z = sum(a, b);
   z = sum(c, d);

   return 0;
}
Here the first call to sum() calls the overload with the int & parameters. The second call to sum() calls the overload with the const int & parameters.
 
  • #10
This is all very interesting. But please don't do this in production code. It will almost certainly create nearly impossible to debug errors in your code.

BoB
 
  • #11
rbelli1 said:
This is all very interesting. But please don't do this in production code. It will almost certainly create nearly impossible to debug errors in your code.

BoB
This. Please for the love of the code gods, this.And nobody seems to have mentioned it yet so I will. There is a HUGE difference between "the compiler let's me do it" and "it's correct C++ code." Most companies much prefer portable code.
 
  • Like
Likes rbelli1
  • #12
newjerseyrunner said:
And nobody seems to have mentioned it yet so I will. There is a HUGE difference between "the compiler let's me do it" and "it's correct C++ code." Most companies much prefer portable code.

True. The stuff we were discussing is well defined by the C++ standard, which every major compiler implements correctly, so there should be no problem.
 
  • #13
TheComet said:
so there should be no problem.

Except when the person that has to maintain your code seeks you out and buries you in the desert.

BoB
 
  • #14
I don't think any of us here believe that the examples shown in this thread follow best practices. They are here purely to answer the question in the OP, about whether two functions have or don't have the same signature. Nothing more.
 
  • #15
Mark44 said:
I don't think any of us here believe that the examples shown in this thread follow best practices. They are here purely to answer the question in the OP, about whether two functions have or don't have the same signature. Nothing more.

I agree. It is good to know this because someone will write code like this and you will need to debug and otherwise untangle it.

These warnings are the same as the warnings that show up in high voltage and other high energy threads.

BoB
 
  • #16
Was it ever made clear if this thread is talking about C or about C++?
 
  • #17
FactChecker said:
Was it ever made clear if this thread is talking about C or about C++?
Not explicit, but we can infer from this prototype in post #1 that we're talking about C++, not C.
C:
int sum(int&a, int&b);
If C has reference parameters as above (not pointers), then I'm not aware of this addition to C.
 
  • #18
It's referring to C++. My Professor said that they are different function signatures, but reading more about it online the ANSI C++ standard says they are the same -- but GNU treats them as being different.
 

Related to Is Pass-by-Reference part of a Function Signature?

What is pass-by-reference in a function signature?

Pass-by-reference in a function signature refers to the way arguments are passed to a function. In this method, the actual variable is passed to the function, rather than a copy of its value. This allows the function to directly modify the original variable's value.

How is pass-by-reference different from pass-by-value in a function signature?

Pass-by-value involves passing a copy of the variable's value to the function, rather than the actual variable itself. This means that any changes made to the variable within the function will not affect the original variable's value outside of the function.

Why is pass-by-reference useful in a function signature?

Pass-by-reference allows for more efficient memory usage, as it does not require copying the variable's value. It also allows for the function to modify the original variable's value, which can be useful in certain situations.

Are there any potential drawbacks to using pass-by-reference in a function signature?

One potential drawback is that it can be more difficult to track changes to the original variable's value, as the function is directly modifying it. This can make debugging more challenging. Additionally, if the function is not well-documented, it may not be clear to other developers that the original variable's value is being modified.

How can I determine if a function uses pass-by-reference in its signature?

To determine if a function uses pass-by-reference, you can check the function's documentation or the source code. If the function accepts arguments with an ampersand (&) before the variable name, it is likely using pass-by-reference. You can also test the function with different types of variables to see if the original variable's value is modified after the function is called.

Similar threads

  • Programming and Computer Science
Replies
2
Views
814
  • Programming and Computer Science
Replies
20
Views
2K
  • Programming and Computer Science
Replies
19
Views
3K
  • Programming and Computer Science
Replies
5
Views
1K
  • Programming and Computer Science
Replies
11
Views
1K
  • Programming and Computer Science
Replies
6
Views
1K
Replies
63
Views
4K
  • Programming and Computer Science
Replies
3
Views
1K
  • Programming and Computer Science
Replies
12
Views
1K
  • Programming and Computer Science
Replies
17
Views
1K
Back
Top