I have the code:
#include "stdafx.h"
#include <iostream>
using namespace std;
void func(const int& a)
{
std::cout << "func(const)" << std::endl;
}
void func(volatile int& a)
{
std::cout << "func(volatile)" << std::endl;
}
void func(const volatile int& a)
{
std::cout << "func(const volatile)" << std::endl;
}
int main()
{
const int a = 0;
const volatile int b = 0;
volatile int c = 0;
func(a);
func(b);
func(c);
system("pause");
return 0;
}
The above code shows overloading based on whether the parameters are const/volatile. However, if I were to change the parameters from int&
to int
, the code no longer compiles and I cannot overload based upon const/volatile parameter types. I dont get why we can overload based on const and volatile if the int is passed by reference, but not if its passed by value?
EDIT I should emphasise I understand what a reference does- I do not understand why a reference alias is allowed to overload on const but a normal int is not.
Perhaps it is useful to take a step back from the functions and just look at the use-cases themselves.
First, we will define an integer and a constant integer for use in our examples:
int anInt = 1;
const int aConstInt = 1;
Next, we take a look at what happens when using these variables to set the values of other integers and constant integers:
int a = anInt; // This works, we can set an int's value
// using an int
int b = aConstInt; // This works, we can set an int's value
// using a const int
const int c = anInt; // This works, we can set a const int's value
// using an int
const int d = aConstInt; // This works, we can set a const int's value
// using a const int
As you can see, there is no way to resolve which overload of a function to select based on behavior (a const int can be accepted by both an int and a const int, and likewise an int can be accepted by both an int and a const int).
Next, we shall take a look at what happens when pass the first set of variables to references:
int& a = anInt; // This works because we are using a
// non-constant reference to access a
// non-constant variable.
int& b = aConstInt; // This will NOT work because we are
// trying to access a constant
// variable through a non-constant
// reference (i.e. we could
// potentially change a constant
// variable through the non-const
// reference).
const int& c = anInt; // This works because we are using a
// constant reference (i.e. "I cannot
// try to change the referenced
// variable using this reference") to
// a non-constant variable.
const int& d = aConstInt; // This will work because we are trying
// to access a constant variable
// through a constant reference.
As you can see, there is some useful behavior that can be had out of distinguishing between an int reference and a const int reference (i.e. disallowing creation of a non-constant reference when a constant reference type is expected).