【问题标题】:Wrong function prototype used by compiler?编译器使用了错误的函数原型?
【发布时间】:2013-06-04 15:45:38
【问题描述】:

我遇到了一个我不明白的编译问题,我将它简化了一点,以便在下面解释。

基本上,它涉及到有 2 个不同的 getter(一个 const 和一个非常量),它们返回一个容器(在本例中是一个映射),分别具有 const 和 non-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

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

非常感谢!

【问题讨论】:

  • FWIW gcc 在同一点抱怨:没有从 'map>' 到 'map>'

标签: c++ map stl constants


【解决方案1】:

如果你真的很好奇,请查看 C++03 标准的第 13.3.3 节,其中描述了如何确定“最佳可行函数”。以下是一些要点:

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

后来:

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

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

要解决这个问题,我会:

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

【讨论】:

  • 感谢 C++ 标准的指针,我选择了这个答案,因为它是最全面的并且有解决方案建议。
  • @Duduche 不幸的是,这个答案是错误的。 non-const 方法被调用。为什么上述标准的引用至关重要?如果不是最佳匹配,您希望编译器调用哪种方法?关键是,如何确定最佳可行函数是什么。
  • 哦,这只是一个错字,已修复。我添加了另一个引文,应该更清楚。
【解决方案2】:

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

这不是“无法”,而是需要选择另一个。

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

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

【讨论】:

    【解决方案3】:

    问题很简单。 pTest 是指向Test 类型对象的指针,它不是 const。因此在调用pTest-&gt;GetObject() 时选择了非常量成员函数,即

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

    如您所见,此函数返回一个std::map&lt;unsigned, TestObjectPair&gt; 类型的值。但是你尝试初始化变量CTO 的类型

    std::map<unsigned, ConstTestObjectPair>
    

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

    【讨论】:

      【解决方案4】:

      C++ 编译器会选择显式覆盖的方法,所以这里 pTest 是一个非常量的可行方法,而 pConstTest 是 const 的。

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

      pTest->GetObject 会选择非常量的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() 将选择 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
      

      【讨论】:

        猜你喜欢
        • 2015-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-19
        • 1970-01-01
        相关资源
        最近更新 更多