web-dev-qa-db-ja.com

非constバージョンではなくconst関数を呼び出す

目的のためにQtの共有データポインタに似たものをラップしようとしましたが、テストの結果、const関数を呼び出す必要があるときに、代わりに非constバージョンが選択されていることがわかりました。

私はC++ 0xオプションでコンパイルしています、そしてここに最小限のコードがあります:

struct Data {
    int x() const {
        return 1;
    }
};

template <class T>
struct container
{
    container() {
        ptr = new T();
    }


    T & operator*() {
        puts("non const data ptr");
        return *ptr;
    }

    T * operator->() {
        puts("non const data ptr");
        return ptr;
    }

    const T & operator*() const {
        puts("const data ptr");
        return *ptr;
    }

    const T * operator->() const {
        puts("const data ptr");
        return ptr;
    }

    T* ptr;
};

typedef container<Data> testType;

void testing() {
    testType test;
    test->x();
}

ご覧のとおり、Data.xはconst関数であるため、演算子->呼び出されるのはconst関数である必要があります。また、const以外のものをコメントアウトすると、エラーなしでコンパイルされるため、可能です。それでも私の端末は印刷します:

「nonconstdataptr」

それはGCCのバグ(私は4.5.2を持っています)ですか、それとも私が欠けているものがありますか?

26
coyotte508

const-nessのみが異なる2つのオーバーロードがある場合、コンパイラは*thisconstであるかどうかに基づいて呼び出しを解決します。サンプルコードでは、testconstではないため、非constオーバーロードが呼び出されます。

これを行った場合:

testType test;
const testType &test2 = test;
test2->x();

test2constであるため、他のオーバーロードが呼び出されることがわかります。

25

testは非constオブジェクトであるため、コンパイラーは最適な一致を見つけます:非constバージョン。ただし、_static_cast_を使用してconstnessを適用できます:static_cast<const testType&>(test)->x();

編集:余談ですが、99.9%の確率でコンパイラのバグを見つけたと思うので、おそらく奇妙な癖があり、コンパイラは実際には標準に準拠しているため、コードを再検討する必要があります。

9
Mark B

Data::xが定数関数であるかどうかは関係ありません。呼び出される演算子は、Dataクラスではなくcontainer<Data>クラスに属し、そのインスタンスは定数ではないため、非定数演算子が呼び出されます。使用可能な定数演算子のみがある場合、またはクラスのインスタンス自体が定数である場合は、定数演算子が呼び出されます。

2
user405725

ただし、testTypeはconstオブジェクトではありません。

したがって、そのメンバーの非constバージョンを呼び出します。
メソッドのパラメーターがまったく同じである場合は、呼び出すバージョンを選択する必要があります(したがって、このパラメーター(非表示のパラメーター)を使用します)。この場合、これはconstではないため、non-constメソッドを取得します。

testType const test2;
test2->x();  // This will call the const version

非constオブジェクトでconstメソッドを呼び出すことができるため、これはx()の呼び出しには影響しません。

0
Martin York