2009-07-07 4 views
7

現在受け入れているC++ 11の機能を習得しようとしており、autoとdecltypeに問題があります。学習の練習として、いくつかの一般的な関数を使ってstdクラスリストを拡張しています。C++でautoとdecltypeを使用する11

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) 

私は、テンプレートクラスを使用せずにマップを定義し、まだそれが返すタイプで、それは一般的な持っているかを把握しようとしています。

答えて

17

std::listまたは他のstd::コンテナからの誘導はお勧めできません。

自由な関数として操作を記述して、イテレーターを介して標準のコンテナーで作業できるようにします。

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

返されるタイプを取得するには、メンバタイプstd::functionを使用できるようにしてください。

また、関数がstd::functionとして渡されることを指定する必要はありません。あなたはどんなタイプでもオープンにしておくことができ、コンパイラにすべてのものを参加させることができます。ランタイムポリモーフィズムにはstd::functionが必要です。

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

あなたのiter関数は、range-based 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ので

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

::リストはコピーコンストラクタのように "move constructor"を持ちますが、引数が一時的なときに選択すると、戻り値の内容を盗むことができます。すなわち、最適なswapと同じです。だからリスト全体のコピーはありません。 (これが、C++ 0xがナイーブに書かれた既存のコードをより速く実行させる理由です。多くの一般的ではあるが醜いパフォーマンスの詐欺は時代遅れになるでしょう)。

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

std::unique_ptr<MyThing> myThing(make_my_thing_somehow()); 
+1

私はベストプラクティスについて尋ねないautoとdecltypeの使い方を学んでいます。 – gradbot

+3

ええ、でも知っていると恩恵を受けるかもしれない他のものがたくさんあります。私は列車の旅の前に私はdecltypeのものに着く前に中断した。今すぐ更新しました。 –

+0

素晴らしい感謝! – gradbot

0

引数の型を演繹する必要がある場合は、関数の自動引数を使用できません。あなたはそのためにテンプレートを使用します。次をご覧ください: 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を使ってうまくいくでしょう。

0

Jarrahが答えてくれた点は、これらの点でこれらの点を正確に説明することだと思います。私はとにかく細部を指摘します:

あなたがこれを行うことはできません、二つのことが間違ってあります

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

autoは、関数の引数には使用できません。関数の型を推測するには、テンプレートを使用する必要があります。 2番目はdecltypeが式を取りますが、_Tyは型です。これを解決する方法は次のとおりです。

template <typename Ret> 
auto 
map(const function<Ret (_Ty)>& f) 
    -> FList<decltype(f(declval<_Ty>()))> 
{} 

このように、タイプのインスタンスを作成する魔法はありません。

関連する問題