2016-04-12 18 views
1

私はこのようになりますクラスだ:私はそう、mapをオーバーロードし、それを引数としてタイプAのゲッターを受け入れることができるようにしようとしている過負荷関数テンプレートパラメータ関数の引数の型に基づいて

template<typename A> 
struct List { 
    ... 
    template<typename Fn, typename B = typename std::result_of<Fn(A)>::type> 
    List<B> map(Fn f) const 
    { ... } 
}; 

foos.map(&Foo::bar)barは、Fooのゲッターです。

template<typename Fn, typename B = typename std::result_of<Fn(A*)>::type> 
List<B> mapGet(Fn getter) const 
{ ... } 
しかし、私は同じ名前 mapを使用しようとすると、コンパイラは、それが曖昧だ文句:以下の機能が動作します。私の質問は、 Fnがゲッターである場合、前に std::result_ofが失敗して、効果的にオーバーロードされた mapのうちの1つを無効にしますか?また、オーバーロードを可能にする方法はありますか? Fn前者 std::result_ofは失敗ではないでしょうゲッターは、効果的にオーバーロードされたマップのいずれかを無効にされたときに

答えて

1

私の質問は、ありますか?

「ゲッター」とは、メンバー関数のポインタです。この場合、std::result_ofはそれらのものとうまく動作します。我々はいくつかのタイプFooを持っているとしましょう:

struct Foo { 
    Foo(int i) : i(i) { } 
    int bar() const { return i; } 
    int i; 
}; 

あなたが期待するようあなたがメンバーへのポインタを使用することができます。

using T = std::result_of_t<decltype(&Foo::bar)(Foo)>; 
static_assert(std::is_same<T, int>{}, "!"); 

唯一の違いは、あなたが実際にfを呼び出す方法です。 C++ 17の場合、すべての呼び出し可能な型で動作するstd::invoke()があります。そうでなければ、直接std::bind()を使うか、同じことをする独自のラッパーを書くことができます。

例として、コピー、転送、および予約を無視して、我々は次のようにmapを書くことができます:

template <class A, class F, class B = std::result_of_t<F(A)>> 
std::vector<B> map(std::vector<A> xs, F f) 
{ 
    auto binder = std::bind(f, std::placeholders::_1); 

    std::vector<B> r; 
    for (auto& x : xs) { 
     r.push_back(binder(x)); 
    } 
    return r; 
} 

実際の関数オブジェクトに対して全く同じように動作することです:

std::vector<int> vs{1, 2, 3, 4, 5}; 
std::vector<double> ds = map(vs, [](int i){return i * 2.0; }); 

それがために行うように我々のFooメンバへのポインタを持つ

std::vector<Foo> foos{1, 2, 3, 4, 5}; 
std::vector<int> is = map(foos, &Foo::bar); 
+0

現在、 mapGet''は '(x。* getter)()'です。ここで 'x'はリストの要素です。私はあなたを得るかどうか分からない。 'map'をオーバーロードすることは可能ですか? –

+0

@ZizhengTai 'map'の2つのオーバーロードは必要ありません。唯一の違いは、各オブジェクトで' f'を呼び出す方法です。他のすべてのロジックは同じです。 – Barry

+0

あなたは何を意味するか分かります! –

関連する問題