9

私は次のようなラッパーをやっています:

#include <iostream>

template<class T, class Value>
void Apply(void (T::*cb)(Value), T* obj, Value v)
{
    (obj->*cb)(v);
}

class Foo
{
public:
    void MyFunc(const int& i)
    {
        std::cout << i << std::endl;
    }

    const int& GetValue()
    {
        return i_;
    }

private:
    int i_ = 14;
};

int main()
{
    Foo f;
    Apply(&Foo::MyFunc, &f, f.GetValue());
}

そして、私はこのエラーが発生しています:

  • Apply: 一致するオーバーロードされた関数が見つかりません。
  • void Apply(void (__thiscall T::* )(Value),T *,Value): テンプレート パラメータがあいまいです。またはValueの可能性があります。 intconst int &
  • void Apply(void (__thiscall T::* )(Value),T *,Value)Value: fromのテンプレート引数を推定できませんでしたconst int

したがって、それはテンプレート パラメーターの推定によるものだとわかりますが、その方法がわかりません。両方の時間に評価されValue ないのはなぜですか?const int&

4

2 に答える 2

13

失敗する理由

現在、テンプレート パラメーターValueは、への呼び出しの 2 つの異なる場所 (Applyメンバー関数の引数へのポインターから、および最後の引数から) で推定されます。から&Foo::MyFuncValueと推定されint const&ます。からf.GetValue()Valueと推定されintます。これは、参照および最上位の cv 修飾子がテンプレート推定のために削除されるためです。パラメータに対するこれら 2 つの推論はValue異なるため、推論は失敗しますApply()。オーバーロード セットから削除され、その結果、実行可能なオーバーロードがなくなります。

修正方法

問題は、それValueが 2 つの異なる場所で推測されることです。そのため、それが起こらないようにしましょう。1 つの方法は、推測されないコンテキストで use の 1 つをラップすることです。

template <class T> struct non_deduced { using type = T; };
template <class T> using non_deduced_t = typename non_deduced<T>::type;

template<class T, class Value>
void Apply(void (T::*cb)(Value), T* obj, non_deduced_t<Value> v)
{
    (obj->*cb)(v);
}

最後の引数 はvnon_deduced_t<Value>その名前が示すように、推定されないコンテキストの型です。したがって、テンプレート推定プロセス中に、はメンバー関数へのポインターから (以前と同様に)Value推定され、それを の型にプラグインするだけです。int const&v

cbまたは、独自のテンプレート パラメーターとして推測することもできます。その時点Apply()で に減少しstd::invoke()ます。

于 2016-11-08T22:05:16.897 に答える
3

f.GetValue()は type の左辺値ですconst int。これが値で渡されると、テンプレート引数推定により type が推定されますint。一般に、Valuefromを推測しても、トップレベルの cv 修飾を持つ参照または型が生成Value vされることはありません。

おそらく、代わりに 2 つの個別のテンプレート パラメーターValue(関数型の引数用に 1 つ、実際の引数の型用に 1 つ) を用意し、SFINAE を使用して(またはハード エラーで)呼び出せないApply場合cbは無効にすることをお勧めします。vstatic_assert

于 2016-11-08T21:51:31.427 に答える