1. ホーム
  2. c++

[解決済み] トランスペアレントコンパレータとは?

2022-09-29 22:25:05

質問

C++14では、連想コンテナはC++11から変更されたようです - [associative.reqmts]/13に書かれています。

メンバー関数のテンプレートである find , count , lower_bound , upper_bound そして equal_range という型がない限り、オーバーロードの解決に参加しないものとします。 Compare::is_transparent が存在しない限り、オーバーロードの解決に参加しない。

コンパレータを "transparent"にする目的は何でしょうか?

C++14ではこのようなライブラリテンプレートも用意されています。

template <class T = void> struct less {
    constexpr bool operator()(const T& x, const T& y) const;
    typedef T first_argument_type;
    typedef T second_argument_type;
    typedef bool result_type;
};

template <> struct less<void> {
    template <class T, class U> auto operator()(T&& t, U&& u) const
    -> decltype(std::forward<T>(t) < std::forward<U>(u));
    typedef *unspecified* is_transparent;
};

ですから、例えば std::set<T, std::less<T>> ではなく は透明なコンパレータを持ちますが std::set<T, std::less<>> があります。

これはどのような問題を解決するのでしょうか、また、標準的なコンテナの動作が変わるのでしょうか。例えば、テンプレートパラメーターの std::set はまだ Key, Compare = std::less<Key>, ... であるため、デフォルトのセットでは find , count などのメンバーですか?

どのように解決するのですか?

<ブロッククオート

どのような問題を解決するのですか。

参照 ディートマールの回答 および リミーベルの回答 .

で、これによって標準的なコンテナの動作が変わるのでしょうか?

いいえ、デフォルトではありません。

新しいメンバー関数テンプレートのオーバーロードは find などでは、キーの型そのものを使うのではなく、コンテナのキーと比較可能な型を使うことができます。 以下を参照してください。 N3465 Joaquín Mª López Muñoz による、この機能を追加するための根拠と詳細かつ慎重に書かれた提案を参照してください。

ブリストルでの会議で、LWG は heteregeneous lookup 機能が有用で望ましいということに合意しましたが、Joaquín の提案がすべてのケースで安全であるとは断言できませんでした。N3465 の提案は、いくつかのプログラムにとって深刻な問題を引き起こしたことでしょう ( 既存のコードへの影響 の項を参照)。Joaquín は、異なるトレードオフを持ついくつかの代替実装を含む最新のドラフト提案を準備し、LWG が長所と短所を理解するのに非常に役に立ちましたが、それらはすべて何らかの形でいくつかのプログラムを破壊するリスクがあったため、その機能を追加することに同意することはできませんでした。 私たちは、無条件に機能を追加するのは安全ではないが、デフォルトで無効にして、" opt in" だけであれば安全であろうと判断しました。

の重要な違いは N3657 提案 (これは、私と STL が N3465 と Joaquín による後の未発表の草稿に基づく) の提案では、この草稿に is_transparent 型を追加することでした。

もしあなたが "透明なファンクタ" (つまり is_transparent 型を定義するもの) を使用しない場合、コンテナはこれまでと同じように動作し、それはまだデフォルトのままです。

もし、あなたが std::less<> (C++14 の新機能) または別の透過型ファンクタ "transparent functor" 型を使用する場合は、新しい機能を使用できます。

使用方法 std::less<> を使うのは、エイリアス テンプレートを使えば簡単です。

template<typename T, typename Cmp = std::less<>, typename Alloc = std::allocator<T>>
  using set = std::set<T, Cmp, Alloc>;

名前 is_transparent はSTLの N3421 から来ており、C++14 に "ダイヤモンド演算子" が追加されました。透明なファンクタとは、任意の引数型(同じである必要はありません)を受け入れ、それらの引数を単に別の演算子に転送するものです。 このようなファンクタは,まさに連想コンテナの異種間ルックアップに必要なもので,そのため,型 is_transparent という型がすべてのダイアモンド演算子に追加され、新しい機能が連想コンテナで有効であることを示すタグ型として使用されました。技術的には、コンテナには "透明なファンクタ" は必要なく、異種型での呼び出しをサポートするものだけです(たとえば pointer_comp の型 https://stackoverflow.com/a/18940595/981959 は、STLの定義によれば透過的ではありません。 pointer_comp::is_transparent を定義することで、問題を解決するために使用することができます)。もし、あなたが一度だけ、あなたの std::set<T, C> のキーで T または int では C という型の引数で呼び出せるだけである。 T そして int (のどちらかであれば)、本当に透明である必要はありません。 私たちがこの名前を使ったのは、より良い名前を思いつかなかったからでもあります(私は、より良い is_polymorphic というのは、このようなファンクタは静的ポリモーフィズムを使うからですが、すでに std::is_polymorphic の型特性は動的ポリモーフィズムを参照しているからです)。