Question

I am trying to understand the rules of c++ automatic and explicit conversions in regular or member function calls. I wrote the following code and it fails compilation:

#include <iostream>
#include <string>

using namespace std;

class testExplicit {
    public:
        int intval;
        short shortval;
        double doubleval;
        char charval;
        string strval;
        testExplicit(int a1, short a2, double a3, char a4, string& a5):
            intval(a1),shortval(a2),doubleval(a3),charval(a4),strval(a5){}

        void getVal(int& a) { a = intval; cout << "IntVal\n"; }
        //        void getVal(short& a) { a = shortval; cout << "Short Val\n"; }
        //        void getVal(double& a) { a = doubleval; cout << "Double Val\n"; }
        //        void getVal(char& a) { a = charval; cout << "Char Val\n"; }
        //        void getVal(string& a) { a = strval; cout << "String Val\n"; }

};

int main( int argc, char **argv ) { 
    string s ("test Str");

    testExplicit test (100,10,10.05,5,s);

    int i;
    char c;
    double d;
    short f;
    test.getVal(i);
    test.getVal(c);
    test.getVal(d);
    test.getVal(f);

    return 0;
}

However, can I conclude that the functions only expect the exact matching parameter? I remember reading that automatic conversions happen according to the conversion rules. Can some shed some light on the correct rules pls?

Here is the error:

test.cpp: In function 'int main(int, char**)':
test.cpp:38: error: no matching function for call to 'testExplicit::getVal(char&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
test.cpp:39: error: no matching function for call to 'testExplicit::getVal(double&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
test.cpp:40: error: no matching function for call to 'testExplicit::getVal(short int&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)

Thanks

Was it helpful?

Solution

void getVal(int& a);

This function takes an int by reference. You must pass it an int. This is similar to how if you had a function

void getVal(int* a);

you would need to pass it a pointer to an int (not a pointer to a short or any other type).

One reason for this is that you are able to modify the int from within the function. In order to allow you to pass an object of another type (e.g. a short) to this function, a temporary object of type short would have to be created at runtime and a reference to that temporary object would have to be passed.

This wouldn't be ideal because you might accidentally end up passing the wrong type of object (e.g. a short) and expecting it to be modified by the function, when in fact a temporary copy of type int would be modified by the function, not the original short.

You are, however, permitted to bind const references to temporary objects, so if your function was declared as

void getVal(const int& a);

you would be able to pass it any type that is convertible to int. This makes some sense, since the function cannot modify the referenced object (because it is a const reference), so the "oops, I'm accidentally modifying a temporary object" problem doesn't exist.

Conversions can also take place when you pass by value, but this too makes sense: when you pass by value, a copy has to be made anyway (the copy that is passed to the function by value), so the conversion can take place as part of that copy.

OTHER TIPS

The problem is that if an implicit conversion is required, then a temporary variable is created. You cannot have a non-const reference to a temporary variable, so you would need to make your member function void getVal(const int &a) or void getVal(int a).

Implicit conversion should be avoided. C++ is a strongly typed language it is far better to create functions for the types you wish to accept, use templates, or explicitly cast your type to another type, etc.

Constructor casting or using static_cast<>, dynamic_cast<>, or reinterpret_cast<> are some of the options depending on the situation when you need to convert types from one to another.

Templates can allow you to handle multiple types a little easier.

template<typename T>
void getVal(const T& a)
{
     // do something
}

Implicit conversions are done by creating an rvalue (temporary), and rvalues cannot be bound to non-const references. That is the reason why it is not working. If, on the other hand you change the signature to take the arguments either by value or by constant reference, then it will work:

void f( int a ) { std::cout << a << std::endl; }
void g( const int& b ) { std::cout << b << std::endl; }
int main() {
   char c = 'a'; // note that this the ASCII value of 'a'
   f( c );
   g( c );
   short s = 4; 
   f( s );
   g( s );
}

Pass by reference means, creating an alias for the same type. So try changing void getVal(int& a) to void getVal(int a), to work for the other function calls differing the passing parameter type

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top