質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

multimapの参照がうまくできない(C++)

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,590

score 45

C++のmultimapにはデータペアを削除する関数がないため、struct v tmp_vのキーに該当する部分をequal_rangeで取り出したのち、その部分からデータがtmp_v_valueに一致するものを削除するプログラムを書きました。以下にその部分のコードを掲載します。
しかしこのプログラムを実行したところ、equal_rangeのイテレータが空になってしまいました。確かにデータは追加したはずなのですが。

struct vと比較演算子の定義もコードの下に載せます。

アドバイスをお願いいたします。

/* 事前にstruct vを定義 */

multimap<struct v, struct v> *nmap = new multimap<struct v, struct v>;
/* ------ いくつかのデータを追加。省略 ------*/

//nmapからtmp_v, tmp_v_valueのペアを持つデータのみを削除するプログラムが以下....
auto range = nmap->equal_range(tmp_v); //tmp_vはstruct v の変数
for (auto it = range.first; it != range.second; ++it) {
    if(it->second == tmp_v_value) {
        nmap->erase(it); //tmp_v_value (tmp_v_valueはstruct vの変数)と一致したらそのイテレータを削除
        break;
    }
}

以下に構造体の定義を追記いたします。

typedef struct v {
    uint8_t first;
    uint8_t second;
    uint8_t third;
    uint8_t fourth;
    inline bool operator >  (const struct v &i) const {
        if (first  > i.first) {
            return true;
        } else if(first == i.first && second > i.second){
            return true;
        } else if(first == i.first && second == i.second && third > i.third){
            return true;
        } else if(first == i.first && second == i.second && third == i.third && fourth > i.fourth){
            return true;
        } else {
            return false;
        }
    }

    inline bool operator >=  (const struct v &i) const {
        if (first >= i.first) {
            return true;

        } else if(first == i.first && second >= i.second){
            return true;

        } else if(first == i.first && second == i.second && third >= i.third){
            return true;

        } else if(first == i.first && second == i.second && third == i.third && fourth >= i.fourth){
            return true;

        } else {
            return false;

        }
    }

    inline bool operator <  (const struct v &i) const {
        if (first > i.first) {
            return false;
        } else if(first == i.first && second > i.second){
            return false;
        } else if(first == i.first && second == i.second && third > i.third){
            return false;
        } else if(first == i.first && second == i.second && third == i.third && fourth > i.fourth){
            return false;
        } else {
            return true;
        }
    }

    inline bool operator <=  (const struct v &i) const {
        if (first  >= i.first) {
            return false;
        } else if(first == i.first && second >= i.second){
            return false;
        } else if(first == i.first && second == i.second && third >= i.third){
            return false;
        } else if(first == i.first && second == i.second && third == i.third && fourth >= i.fourth){
            return false;
        } else {
            return true;
        }
    }

    inline bool operator == (const struct v &i) const {
        if (first  == i.first  && second == i.second && third  == i.third  && fourth == i.fourth) {
            return true;
        } else {
            return false;
        }
    }

    inline bool operator != (const struct v &i) const {
        if (first  != i.first || second != i.second || third  != i.third || fourth != i.fourth) {
            return true;
        } else {
            return false;
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

(あまりにコードが煩雑なため検証まで行っていませんが)struct voperator<定義が正しくない、つまりstd::multimap<Key,T>キー型Keyが満たすべき"Strict Weak Ordering"要件を満足しないように見えます。

C++標準ライブラリの連想コンテナでは「より小さい(<)」演算子の定義が最も重要です。ただし"Strict Weak Ordering"要件を正しく実装するのは非常に難しいため、<tuple>ヘッダで提供されるstd::tie関数の利用を推奨します。また、その他の大小比較演算子(>,<=,=>)定義も独自コードで行うのではなく、前述の「より小さい(<)」演算子を用いて定義すべきです。同様に、!=演算子は==演算子を用いて定義すべきです。

#include <tuple>  // std::tie

struct v {
    uint8_t first;
    uint8_t second;
    uint8_t third;
    uint8_t fourth;

    // 大小比較演算子
    inline bool operator<(const v& rhs) const {
        return std::tie(first, second, third, fourth)
               < std::tie(rhs.first, rhs.second, rhs.third, rhs.fourth);
    }
    inline bool operator>(const v& rhs) const {
        return rhs.operator<(*this);
    }
    inline bool operator<=(const v& rhs) const {
        return !rhs.operator<(*this);
    }
    inline bool operator>=(const v& rhs) const {
        return !operator<(rhs);
    }

    // 等価比較演算子
    inline bool operator==(const v& rhs) const {
        return std::tie(first, second, third, fourth)
               == std::tie(rhs.first, rhs.second, rhs.third, rhs.fourth);
    }
    inline bool operator!=(const v& rhs) const {
        return !operator==(rhs);
    }
};

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

こんにちは。

比較演算子が記載される前に、ちょっとやってみました。問題ないようです。
下記のフリー関数の代わりにメンバ関数を定義するとコンパイルエラーになりますので、メンバ関数のoperator< は使われないようです。(std::lessの実装がそういうものなのかも。)
つまり、お使いの環境でフリー関数としてのbool operator<(v const&, v const&)が定義されているのかも知れません。
Compairにメンバ関数のoperator<を使う比較関数を明示的に指定すれば意図通りに動作するかもです。

#include <iostream>
#include <map>
#include <string>

struct v
{
    std::string x;
    v(std::string const& str) : x(str) { }
    friend bool operator<(v const& iLhs, v const& iRhs)
    {
        return iLhs.x < iRhs.x;
    }
    bool operator==(v const& iRhs)
    {
        return x == iRhs.x;
    }
};

int main()
{
    std::multimap<struct v, struct v> nmap =
    {
        {v("a"), v("1")},
        {v("b"), v("2")},
        {v("b"), v("3")},
        {v("b"), v("4")},
        {v("c"), v("5")},
    };

    v   tmp_v("b");
    v   tmp_v_value("3");

    std::cout << "----------\n";
    for (auto elm : nmap)
    {
        std::cout << elm.first.x << ", " << elm.second.x << "\n";
    }
    //nmapからtmp_v, tmp_v_valueのペアを持つデータのみを削除するプログラムが以下....
    auto range = nmap.equal_range(tmp_v); //tmp_vはstruct v の変数
    for (auto it = range.first; it != range.second; ++it) {
        if(it->second == tmp_v_value)
        {
            nmap.erase(it); //tmp_v_value (tmp_v_valueはstruct vの変数)と一致したらそのイテレータを削除
            break;
        }
    }

    std::cout << "----------\n";
    for (auto elm : nmap)
    {
        std::cout << elm.first.x << ", " << elm.second.x << "\n";
    }
}

結果:

----------
a, 1
b, 2
b, 3
b, 4
c, 5
----------
a, 1
b, 2
b, 4
c, 5

wandbox

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る