Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong function prototype used by compiler?

I faced a compilation problem that I do not understand, I have simplified it a bit for explanation below.

Basically, it involves having 2 different getters (a const and non-const one) that return a container (a map in this example) with const, respectively non-const value_type.

What puzzles me is that in the example below, the compiler seems unable to use the const getter on a non-const object:

#include "stdafx.h"
#include <utility>
#include <map>

class TestObject
{
public:

    TestObject() {}
    virtual ~TestObject() {}
};

typedef std::pair<const TestObject*, const TestObject*> ConstTestObjectPair;
typedef std::pair<TestObject*, TestObject*> TestObjectPair;

class Test
{
    TestObject* m_pObject;

public:

    Test() {m_pObject = new TestObject();}
    virtual ~Test() {delete m_pObject;}

    std::map<unsigned, ConstTestObjectPair> GetObject() const
    {
        std::map<unsigned, ConstTestObjectPair> map;
        map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
        return map;
    }

    std::map<unsigned, TestObjectPair> GetObject()
    {
        std::map<unsigned, TestObjectPair> map;
        map.insert(std::make_pair(0, std::make_pair(m_pObject, m_pObject)));
        return map;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Test* pTest = new Test();
    const Test* pConstTest = pTest;

    std::map<unsigned, ConstTestObjectPair> CTO = pTest->GetObject(); // Not compiling, I don't get why!!!
    CTO = pConstTest->GetObject();

    std::map<unsigned, TestObjectPair> TO = pTest->GetObject();
    //TO = pConstTest->GetObject(); // Not working, this is expected

    return 0;
}

I tried with both VS2010 and gcc and neither accepts to compile this code. Here is the compilation error returned by VS2010:

1>c:\test.cpp(48): error C2440: 'initializing' : cannot convert from 'std::map<_Kty,_Ty>' to 'std::map<_Kty,_Ty>'
1>          with
1>          [
1>              _Kty=unsigned int,
1>              _Ty=TestObjectPair
1>          ]
1>          and
1>          [
1>              _Kty=unsigned int,
1>              _Ty=ConstTestObjectPair
1>          ]
1>          No constructor could take the source type, or constructor overload resolution was ambiguous

Could someone explain me why the compiler cannot find/use the correct prototype on the non-const object?

Thanks a lot!

like image 756
Duduche Avatar asked Jun 04 '13 15:06

Duduche


People also ask

What function prototype tells the compiler?

The function prototypes are used to tell the compiler about the number of arguments and about the required datatypes of a function parameter, it also tells about the return type of the function. By this information, the compiler cross-checks the function signatures before calling it.

What is the correct prototype of function?

A function prototype is a definition that is used to perform type checking on function calls when the EGL system code does not have access to the function itself. A function prototype begins with the keyword function, then lists the function name, its parameters (if any), and return value (if any).

What is the error of prototype?

It is an error if the number of arguments in a function definition, declaration, or call does not match the prototype. If the data type of an argument in a function call does not match the corresponding type in the function prototype, the compiler tries to perform conversions.

Which of the following is an invalid function prototype?

1 Answer. (a) void fun (intx);


1 Answers

If you're really curious, check out section 13.3.3 of the C++03 standard, which describes how the "best viable function" is determined. Here are some important points:

The selection criteria for the best function are the number of arguments, how well the arguments match the types of the parameters of the candidate function, how well (for nonstatic member functions) the object matches the implied object parameter, and certain other properties of the candidate function. [Note: the function selected by overload resolution is not guaranteed to be appropriate for the context. Other restrictions, such as the accessibility of the function, can make its use in the calling context ill-formed. ]

And later:

If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution

Note that the return type of the function is not mentioned in this criteria. So the non-const method is selected as most valid, because its "implied object parameter" (essentially the "this" pointer) is non-const. This all happens before the conflict with the return type is detected.

To solve this problem, I would either:

  • Change your design so that ConstTestObjectPair isn't needed, and you can just use const TestObjectPair (preferred solution)
  • Cast your non-const objects to const ones when needed
like image 66
Taylor Brandstetter Avatar answered Sep 20 '22 01:09

Taylor Brandstetter