0

私の状況:

1 つのフィールドをキーまたは ID と見なすことができる構造のベクトルが必要になることがよくありますが、高価なマップに格納するのではなく (このアプリではメモリ使用量が非常に重要です)、フラットなベクトルに格納したいと考えています。キーで要素を見つけるためのマップのようなインターフェイスを提供します。

この問題に対する私の最初の解決策:

template <class T, class Key, class KeyFn>
class TKeyedVector : public std::vector<T>
{
public:

    const_iterator      find(const Key& key) const {return std::find_if(begin(), end(), [&](const T& entry) {return keyFn(entry)==key; }); }

    KeyFn keyFn;
};

struct KeyedDataEntry
{
  std::string       key;
  int               value;

  struct KeyExtractor {
    const std::string& operator()(const KeyedDataEntry& e) const {return e.key; };
  };
};

using KeyedDataArray = TKeyedVector<KeyedDataEntry, std::string, KeyedDataEntry::KeyExtractor>;

KeyExtractorこれですべて機能しますが、型に埋め込まれたメンバー変数へのポインターを使用して、型の必要性をなくしたいと考えています。

template <class T, class Key, Key T::* keyFn>
class TKeyedVector : public std::vector<T>
{
public:
        const_iterator      find(const Key& key) const {return std::find_if(begin(), end(), [&](const T& entry) {return keyFn(entry)==key; }); }
};

using KeyedDataArray = TKeyedVector<KeyedDataEntry, std::string, &KeyedDataEntry::key>;

しかし、私はこれを機能させることができません。手がかりのための実装を見てきましたがstd::mem_fn、それを行う方法がわかりません。私が得るエラーは次のようなものです:

 warning C4353: nonstandard extension used: constant 0 as function expression.  Use '__noop' function intrinsic instead

手がかりはありますか?

編集: http://ideone.com/Qu6TEyのサンプル バージョン

4

2 に答える 2

1

メンバーへのポインターには、メンバー呼び出し構文へのポインターが必要です。(entry.*keyFn)()

C++17 には、std::invokeこのようなテンプレートを作成する手間を少し軽減する標準関数が付属しています (呼び出し可能なすべてのオブジェクトで機能します)。しかし、その間、これはあなたがこれを行う必要がある方法です。

于 2016-09-05T16:50:51.600 に答える
1

これが実用的なソリューションの始まりです。特別な抽出オブジェクトは必要ありません。

ベクトルをカプセル化したことに注意してください。やがて、これをしなかったことを後悔するでしょう。

#include <vector>
#include <string>

template <class T, class Key, const Key& (T::*Extractor)() const>
class TKeyedVector
{
    using storage = std::vector<T>;
    using const_iterator = typename storage::const_iterator;
public:

    decltype(auto) begin() const
    {
        return storage_.begin();
    }

    decltype(auto) end() const
    {
        return storage_.end();
    }

    const_iterator find(const Key& key) const
    {
        return std::find_if(begin(),
                            end(),
                            [&](const T& entry)
        {
            return entry.*Extractor() == key;
        });
    }

    storage storage_;
};

struct KeyedDataEntry
{
    std::string       key;
    int               value;

    const std::string& get_key() const { return key; }

};

int main()
{
    TKeyedVector<KeyedDataEntry, std::string, &KeyedDataEntry::get_key> mymap;

}

しかし、あなたのこの考えには問題があります。

この構造をマップにするためには、キーが不変でなければなりません。これは、不変オブジェクトのみを返すことを主張しています。unordered_setこれは、単にorを使用することをすぐに主張しsetます。

基になるベクトル内の変更可能なオブジェクトへの参照を返す場合は、単純std::find_ifに述語を使用してそれらを見つけることもできます。

于 2016-09-05T17:06:42.767 に答える