Incorrect function prototype used by the compiler?

I ran into a compilation problem that I don't understand, I simplified it for explanation below.

In principle, it includes the presence of two different getters (const and non-const one) that return a container (a map in this example) with a constant, respectively, not a constant value_type.

What puzzles me is that in the example below, the compiler cannot use const getter for a non-constant 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 none of them accepts compiling 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 

Can someone explain to me why the compiler cannot find / use the correct prototype for a non-constant object?

Thanks a lot!

+6
source share
4 answers

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

The selection criteria for the best function is the number of arguments, how much the arguments correspond to the types of parameters of the candidate function, how well (for non-static member functions) the object matches the parameter of the implied object and some other properties of the candidate function. [Note: the function selected by overload resolution is not guaranteed for the context. Other restrictions, such as the availability of a function, can make its use in a calling context poorly formed. ]

And later:

If there is exactly one viable function that is a better function than all other viable functions, then this one is selected using overload resolution

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

To solve this problem, I would like to:

  • Change your design so that ConstTestObjectPair not needed and you can just use const TestObjectPair (preferred solution)
  • Pull your non-constant objects into constant objects if necessary
+5
source

What puzzles me is that in the example below, the compiler doesn't seem to be able to use const getter on a non-const object

He is not "incapable", but must choose another.

Overload is selected using the transferred actual parameters. For a member function, including the hidden parameter used for this . For T *, non-constant overload is selected, if you want another, you must use const T * by pressing or in other ways.

In fact, a common mistake is that the type of the return value will be used in some way, and a function that returns what you want to use in the expression will be selected. This is simply not so.

+4
source

The problem is pretty simple. pTest is a pointer to an object of type Test , which is not const . Therefore, in the call to pTest->GetObject() , the non-const member function is selected, i.e.

 std::map<unsigned, TestObjectPair> GetObject() 

As you can see, this function returns a value of type std::map<unsigned, TestObjectPair> . But then you try to initialize a CTO variable of type

 std::map<unsigned, ConstTestObjectPair> 

with this value. To do this, the compiler needs to convert the return value to this type. But there is no conversion constructor for this. And it reports a compiler error.

+1
source

The C ++ compiler will choose an explicit override method, so here pTest is non-constant and pConstTest is constant.

 Test* pTest = new Test(); const Test* pConstTest = pTest; 

pTest-> GetObject will select the non-constant GetObject:

 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; } 

pConstTest-> GetObject () will select const GetObject:

 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; } 

The first error occurred when you assigned the returned

 std::map<unsigned, TestObjectPair> value 

before

 std::map<unsigned, ConstTestObjectPair> viable 
0
source

Source: https://habr.com/ru/post/946520/


All Articles