8

現在受け入れられているc++11の機能を学習しようとしていますが、autoとdecltypeに問題があります。学習演習として、いくつかの総称関数を使用してstdクラスリストを拡張しています。

template<class _Ty, class _Ax = allocator<_Ty>>
class FList : public std::list<_Ty, _Ax>
{
public:
    void iter(const function<void (_Ty)>& f)
    {
        for_each(begin(), end(), f);
    }

    auto map(const function<float (_Ty)>& f) -> FList<float>*
    {
        auto temp = new FList<float>();

        for (auto i = begin(); i != end(); i++)
            temp->push_back(f(*i));

        return temp;
    }
};

auto *ints = new FList<int>();
ints->push_back(2);
ints->iter([](int i) { cout << i; });

auto *floats = ints->map([](int i) { return (float)i; });
floats->iter([](float i) { cout << i; });

メンバーマップの場合、渡された関数が何を返すかに応じて、戻り型を汎用にする必要があります。したがって、リターンタイプの場合、このようなことを行うことができます。

auto map(const function<float (_Ty)>& f) -> FList<decltype(f(_Ty))>*

これは、関数テンプレートのfloatタイプも削除する必要があります。

auto map(const function<auto (_Ty)>& f) -> FList<decltype(f(_Ty))>*

テンプレートクラスを使用することもできますが、リターンタイプを指定する必要があるため、インスタンスの使用がより冗長になります。

template<class T> FList<T>* map(const function<T (_Ty)>& f)

私の質問を要約すると、テンプレートクラスを使用せずにマップを定義し、それが返すタイプでジェネリックにする方法を理解しようとしています。

4

3 に答える 3

18

std::listまたは他のstd::コンテナからの派生は推奨されません。

操作をフリー関数として記述して、イテレータを介して任意の標準コンテナで動作できるようにします。

「テンプレート関数を使わずにマップを定義する」ということですか?

result_typeのメンバー型を使用しstd::functionて、それが返す型を取得できるはずです。

また、関数が として渡されることを指定する必要はありませんstd::function。任意の型として開いたままにし、コンパイラにすべてを結合させることができます。std::functionランタイム ポリモーフィズムのみが必要です。

new を使用して生のヒープ割り当てオブジェクトを作成し、それらをポインターで返すのは 1992 年です。:)

iter 関数は、範囲ベースの for loopと本質的に同じものです。

でもそれはさておき…こういうことですか?

template <class TFunc>
auto map(const TFunc &f) -> FList<decltype(f(_Ty()))>*
{
    auto temp = new FList<decltype(f(_Ty()))>();

    for (auto i = begin(); i != end(); i++)
        temp->push_back(f(*i));

    return temp;
}

これは、呼び出し可能なものすべてに一致し、decltype を使用して関数の戻り値の型を特定します。

_Ty がデフォルトで構築可能である必要があることに注意してください。インスタンスを作成することで、これを回避できます。

template <class T>
T make_instance();

それを呼び出すコードが生成されないため、実装は必要ありません。したがって、リンカーは文句を言う必要はありません (これを指摘してくれた dribeas に感謝します!)。

したがって、コードは次のようになります。

FList<decltype(f(make_instance<_Ty>()))>*

または、文字通り、_Ty のインスタンスへの参照を使用して関数 f を呼び出して得られる型のリストです。

そして、受け入れるための無料ボーナスとして、右辺値参照を調べてください - これらはあなたが書くことができることを意味します:

std::list<C> make_list_somehow()
{
    std::list<C> result;
    // blah...
    return result;
}

そして、次のように呼び出します。

std::list<C> l(make_list_somehow());

std::list には「移動コンストラクター」(コピー コンストラクターのようなものですが、ここのように引数が一時的な場合に選択される) があるため、戻り値の内容を盗むことができます。つまり、optimal と同じことを行いますswap。したがって、リスト全体のコピーはありません。(これが、単純に書かれた既存のコードを C++0x がより高速に実行する理由です - 多くの一般的で醜いパフォーマンスのトリックは時代遅れになります)。

を使用することで、正しい移動コンストラクターを記述する必要なく、独自の既存のクラスに対して同じ種類のものを無料で取得できますunique_ptr

std::unique_ptr<MyThing> myThing(make_my_thing_somehow());
于 2009-07-07T18:45:40.170 に答える
0

引数の型を推測する関数の引数で auto を使用することはできません。そのためにテンプレートを使用します。http://thenewcpp.wordpress.com/2011/10/18/the-keyword-auto/および http://thenewcpp.wordpress.com/2011/10/25/decltype-and-declval/をご覧ください。 . どちらも auto と decltype の使用方法を説明しています。それらは、それらがどのように使用されるかについて十分な情報を提供する必要があります。特に、make_instance に関する別の回答は、declval を使用するとより適切に実行できます。

于 2011-10-26T20:46:55.470 に答える