4

私はテンプレートについて学んでおり、このメソッドを実装しようとしました:

template <typename Func, typename Left, typename Right>
void flipArgs(Func* function, Left&& leftArg, Right&& rightArg) {
    function(std::forward<Right>(rightArg), std::forward<Left>(leftArg));
}

関数と 2 つのパラメーターを取り、2 つのパラメーターを反転して指定された関数を呼び出します。

次のような関数で正常に動作します。

void test1(std::string, int) {
}

この機能を試したとき:

template <typename T>
void test2(T&& a, int) {
}

と:

string s("test");
flip(test2<string>, 42, s);

コンパイラ(g ++ 4.7.1)は私に教えてくれます:

エラー: 'std::basic_string' 左辺値を 'std::basic_string&&' にバインドできません

のような関数パラメーターは、バインドして参照T&&できる特殊なケースだと思いましたか? 私は何を間違っていますか?rvaluelvalue

4

1 に答える 1

7

のような関数パラメータT&&は [rvalues and lvalues] にバインドできる特別なケースだと思いましたか?

です。これは基本的に、テンプレートが左辺値と右辺値に対して異なるインスタンス化を持つことができることを意味します。

ただし...明示的にTbe stringinにすると、特定のインスタンス化が1 つtest2<string>選択されます。はもはや特別なケースではありません。文字列の右辺値にのみバインドできます。右辺値と左辺値の両方にバインドする 1 つのインスタンス化はありません。void test2(string&&, int)string&&string&&

一般に、関数テンプレート パラメーターを明示的に渡すことはお勧めしません (std::forwardまたはのように意図されている場合を除きますstd::make_unique)。

この場合、代わりに左辺値にバインドするインスタンス化の 1 つを強制することができます。flip(test2<string&>, 42, s);インスタンス化するのようなものvoid test2(string&, int)

flip左辺値と右辺値の両方を受け入れることができる引数を本当に渡したい場合は、多相関数オブジェクトが必要です。

struct test2 {
    template <typename T>
    void operator()(T&& a, int) const {
    }
};
flip(test2{}, 42, s);

ここで重要なのは、どの特殊化を使用するかの決定は、引数を渡すときに行われるのではなく、後でその引数が使用されるときにのみ行われるということです。

完全を期すために、C++14 では実際に、新しいラムダ構文を使用して無名の多相関数オブジェクトを作成できます。

auto test2 = [](auto&& a, int) {};
flip(test2, 42, s);
于 2013-10-22T11:41:09.720 に答える