编译器使用错误的函数原型?

时间:2013-06-04 15:45:39

标签: c++ map stl const

我遇到了一个我不理解的编译问题,我已经将其简化了一点,以供下面的解释。

基本上,它涉及两个不同的getter(一个const和一个const),它们返回一个容器(在这个例子中是一个映射),它们分别是const,非const value_type。

让我感到困惑的是,在下面的示例中,编译器似乎无法在非const对象上使用const getter:

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

我尝试使用VS2010和gcc,但都不接受编译此代码。以下是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

有人可以解释一下为什么编译器无法在非const对象上找到/使用正确的原型吗?

非常感谢!

4 个答案:

答案 0 :(得分:5)

如果您真的很好奇,请查看C ++ 03标准的第13.3.3节,该标准描述了如何确定“最佳可行功能”。以下是一些重点:

  

最佳函数的选择标准是参数的数量,参数的好坏程度   匹配候选函数的参数类型,如何(对于非静态成员函数)   object匹配隐含的对象参数以及候选函数的某些其他属性。 [注意:   由重载决策选择的函数不保证适合上下文。其他   限制(例如函数的可访问性)可以使其在调用上下文中的使用不正确。 ]

后来:

  

如果只有一个可行功能比所有其他可行功能更好,那么它就是   一个由重载决议选择的

请注意,此条件中未提及函数的返回类型。因此,非const方法被选为最有效的方法,因为它的“隐含对象参数”(本质上是“this”指针)是非const的。这一切都发生在检测到与返回类型的冲突之前。

要解决这个问题,我会:

  • 更改您的设计,以便不需要ConstTestObjectPair,您可以使用const TestObjectPair(首选解决方案)
  • 在需要时将非const对象转换为常量对象

答案 1 :(得分:4)

  

让我感到困惑的是,在下面的示例中,编译器似乎无法在非const对象上使用const getter

它不是&#34;无法&#34;但要求选择另一个。

使用传递的实际参数选择重载。对于成员函数,包括用于this的隐藏参数。对于T *,选择非const重载,如果你想要另一个,你必须通过强制转换或其他方式使用const T *。

实际上,认为返回类型将以某种方式使用并且返回要在表达式中使用的内容的函数被选中是一个常见的错误。事实并非如此。

答案 2 :(得分:1)

问题很简单。 pTest是指向Test类型对象的指针,该对象不是const 。因此,在调用pTest->GetObject()中,选择了非const成员函数,即

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

如您所见,此函数返回类型std::map<unsigned, TestObjectPair>的值。但是,您尝试初始化类型

的变量CTO
std::map<unsigned, ConstTestObjectPair>

有这个值。为此,编译器需要将返回的值转换为此类型。但是没有转换构造函数可以做到这一点。这就是编译器错误告诉你的。

答案 3 :(得分:0)

C ++编译器将选择显式覆盖方法,因此这里pTest是非const可行的,pConstTest是const。

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

pTest-&gt; GetObject将选择非const 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-&gt; GetObject()将选择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;
}

分配返回的

时发生第一个错误
std::map<unsigned, TestObjectPair> value 

std::map<unsigned, ConstTestObjectPair> viable