読者です 読者をやめる 読者になる 読者になる

C++1z 連想コンテナ用のデフォルトの順序付け

C++

mapsetのキーとなる型はデフォルトで、operator<で比較できる必要があります。連想コンテナのキーにできるようにするために、ユーザー定義型にoperator<を定義することもありますが、その比較演算を連想コンテナ以外の用途では使わないことが多々あります。

連想コンテナ用の比較演算とそうでない比較演算で用途を分けられるようにするために、C++1zではdefault_orderという中間インタフェースの型が定義されます。

// <functional>
namespace std {
    template <class T = void>
    struct default_order {
        using type = std::less<T>;
    };

    template <class T = void>
    using default_order_t = typename default_order<T>::type;
}

そして、連想コンテナの比較演算関数オブジェクトは、std::lessクラスを直接使用するのではなく、default_orderを介してstd::lessを使用するよう変更されます。これによるABIの破壊はありません。

// <map>
namespace std {
    template <class Key, class T, class Compare = default_order_t<Key>,
            class Allocator = allocator<pair<const Key, T>>>
    class map;

    template <class Key, class T, class Compare = default_order_t<Key>,
              class Allocator = allocator<pair<const Key, T>>>
    class multimap;
}
// <set>
namespace std {
    template <class Key, class Compare = default_order_t<Key>,
              class Allocator = allocator<Key>>
    class set;


    template <class Key, class Compare = default_order_t<Key>,
              class Allocator = allocator<Key>
    class multiset;
}
// <queue>
namespace std {
    template <class T, class Container = vector<T>,
              class Compare = default_order_t<typename Container::value_type>>
    class priority_queue;
}

型を連想コンテナのキーとして使用できるようにするためだけに順序付けしたい場合は、default_orderを特殊化して順序判定用の関数オブジェクトを使用するよう指定することになります。

namespace sales {
    struct account {
        int id;
        std::string name;
    };

    // 連想コンテナで順序付けするための関数オブジェクト
    struct order_accounts {
        bool operator()(const Account& lhs, const Account& rhs) const {
            return lhs.id < rhs.id;
        }
    };
}

namespace std {
    // sales::account型については、
    // sales::order_account関数オブジェクトでキーの順序付けをする
    template<>
    struct default_order<sales::account>
        using type = sales::order_accounts;
    };
}

int main()
{
    std::set<sales::account> s;
}

教科書的な説明がむずかしくなるので、ちょっと困りますね。advancedな用途と考えて、初心者向けには従来の方法を説明するのがよさそうです。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。