1

参照の転送に関するこの投稿を開きました。これは (うまくいけば) MCVE コードです。

#include <functional>
#include <vector>

using namespace std;
struct MultiMemoizator {
    template <typename ReturnType, typename... Args>
    ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) {

    }
};

typedef vector<double> vecD;

vecD sort_vec (const vecD& vec) {
    return vec;
}

int main()
{
    vecD vec;
    std::function<vecD(const vecD&)> sortFunc(sort_vec);
    MultiMemoizator mem;
    mem.callFunction<vecD, vecD>(sortFunc, vec);
}

これはコード全体ではないため、回答に基づいてコードを追加する必要があるかもしれません。

とにかく、この回答で示唆されているように、このバージョンでは転送参照はできませArgsん。

だから私の質問は: このコードを「転送参照可能」にすることは可能ですか?

4

2 に答える 2

2

引数を完全転送するには、型を推定する必要があります。これを行うには、関数への引数とファンクターへのパラメーターを別々に推定します。

template <typename ReturnType, typename... FunArgs, typename... Args>
ReturnType callFunction(std::function<ReturnType(FunArgs...)> memFunc,
                        Args&&... args) 
{
    //...
}

次に、callFunctionテンプレート パラメーターなしで呼び出して、すべてを推測できます。

mem.callFunction(sortFunc, vec);
于 2016-04-25T15:01:34.323 に答える
0

コードがコンパイルに失敗する理由(明示的なテンプレートパラメーターがなくても)だけでなく、(私自身の意見では)コードが危険である理由について、@TartanLlamaの回答に関する詳細を少し追加します。

以下では、説明が簡単で意味が変わらないためT、パラメーターパックの代わりに単純な型のみを使用します。Args...

転送参照に関するちょっとしたメモ...

まず、次の単純な例よりも簡単な例を見てみましょう。

template <typename T>
void f (T&&);

さて、fさまざまなソースからインスタンス化しましょう。次の変数があると仮定しましょう。

std::string s;
const std::string cs;

...それから:

f(s); // instanciate f<std::string&>
f(cs); // instanciate f<const std::string&>
f(std::string()); // instanciate f<std::string&&>

あなたは疑問に思うはずです:なぜ最初のインスタンス化がf<std::string&>ではなくf<std::string>? 、しかし標準はあなたに伝えます(§14.8.2.1#3 [temp.deduct.call]):

P が転送参照で、引数が左辺値の場合、型推定のために A の代わりに「A への左辺値参照」型が使用されます。

最初のスニペットに戻りましょう。

ここで、例を少し複雑にしましょう。

template <typename T> 
struct A {};

template <typename T>
void f (A<T>, T&&);

そして 1 つのインスタンス化:

std::string s;
A<std::string> as;
f(as, s);

上記はあなたの例と同等で、コンパイルに失敗しますが、なぜ... ? 上で説明したように、lvalueがある場合、推定された型T&&T&ではないためT、型推定は失敗します。A<T>これは、コンパイラが期待していA<std::string&>A<std::string>.

これで、次のことを行う必要があることがわかりました。

A<std::string&> ars;
A<std::string const&> acrs;
f(ars, s); // good
f(acrs, cs); // good

なぜ危険なのですか?

さて、これは良いはずです:

A<std::string&&> arrs;
f(arrs, std::string());

しかし、そうではありません... whenTは右辺値参照として推定されるため、T単純Tに であるため、コンパイラは を期待していA<std::string>ます。

ここに問題があります:左辺値を期待する関数に転送するメソッドに右辺値を与えようとしています。それは間違いではありませんが、おそらくあなたが期待していたものではありません。

それに対処する方法は?

最初の可能性は、 の推定型に関係なく、最初のパラメーターの型を強制することですT。たとえば、次のようになります。

template <typename T>
void f (A<typename std::remove_reference<T>::type>, T&&);

ただし、次の点に注意してください。

  1. 対処するものをさらに追加する必要がありconstます。
  2. 最初の引数の型が固定されている場合の有用性を疑問に思うかもしれませんT&&(少なくともあなたの場合)。

2 番目の可能性 (警告: これが標準かどうかはわかりません! ) は、最初のパラメーターを最後に移動してから、型を推測することですt

template <typename T>
void f (T &&t, A<decltype(std::forward<T>(t))>);

Tこれで、 の推定型と の期待型が完全に一致しましたA

残念ながら、上記を可変個引数テンプレートで機能させる方法がわかりません...

于 2016-04-25T20:00:16.280 に答える