6

理解できないコンパイルの問題に直面しました。以下の説明のために少し簡略化しました。

基本的に、2 つの異なるゲッター (const と非 const のゲッター) があり、const と non-const の value_type を持つコンテナー (この例ではマップ) を返します。

私が困惑しているのは、以下の例では、コンパイラが非 const オブジェクトで const ゲッターを使用できないように見えることです。

#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

4 に答える 4

5

本当に興味がある場合は、C++03 標準のセクション 13.3.3 を調べてください。このセクションでは、「実行可能な最適な関数」がどのように決定されるかが説明されています。ここにいくつかの重要な点があります:

最適な関数の選択基準は、引数の数、引数が候補関数のパラメーターの型とどの程度一致するか、(非静的メンバー関数の場合) オブジェクトが暗黙のオブジェクト パラメーターとどの程度一致するか、および関数のその他の特定のプロパティです。候補関数。[注: オーバーロードの解決によって選択された関数は、コンテキストに適しているとは限りません。関数のアクセシビリティなどのその他の制限により、呼び出しコンテキストでの使用が不適切になる可能性があります。]

以降:

他のすべての実行可能な関数よりも優れた関数である実行可能な関数が 1 つだけある場合、それはオーバーロードの解決によって選択された関数です。

関数の戻り値の型は、この基準では言及されていないことに注意してください。そのため、「暗黙のオブジェクト パラメーター」(本質的には「this」ポインター) が非定数であるため、非定数メソッドが最も有効なものとして選択されます。これはすべて、戻り値の型との競合が検出される前に発生します。

この問題を解決するには、次のいずれかを行います。

  • 必要がないようにデザインを変更し、ConstTestObjectPairそのまま使用できるようにしますconst TestObjectPair(推奨されるソリューション)
  • 必要に応じて、非 const オブジェクトを const オブジェクトにキャストします
于 2013-06-04T16:12:04.020 に答える
1

問題は非常に単純です。constではないpTesttype のオブジェクトへのポインタです。したがって、呼び出しでは、非 const メンバー関数が選択されます。つまり、TestpTest->GetObject()

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

ご覧のとおり、この関数は type の値を返しますstd::map<unsigned, TestObjectPair>。しかし、その後CTO、タイプの変数を初期化しようとします

std::map<unsigned, ConstTestObjectPair>

この値で。そのために、コンパイラは戻り値をこの型に変換する必要があります。しかし、それを行う変換コンストラクターはありません。そして、それがコンパイラエラーが教えてくれることです。

于 2013-06-04T16:29:00.533 に答える
0

C++ コンパイラは明示的にオーバーライドされたメソッドを選択するため、ここで pTest は非 const 実行可能であり、pConstTest は const 1 です。

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

pTest->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->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
于 2013-06-04T16:26:13.183 に答える