C++におけるstd::moveとstd::forwardの実装と使い方

std::move は、任意の式を右値参照に変換するユーティリティ関数であり、コピーではなくムーブセマンティクスを有効にするために使用される。以下はその簡易実装例である:

template <typename T>
constexpr typename std::remove_reference<T>::type&&
my_move(T&& value) noexcept {
    return static_cast<typename std::remove_reference<T>::type&&>(value);
}

この関数は、引数の参照性を除去した型に対して右値参照を返す。これにより、呼び出し元で明示的に「このオブジェクトはもう使わないので資源を移動してよい」と指示できる。

一方、std::forward は「完全転送(perfect forwarding)」を実現するための関数で、テンプレート引数の型情報に基づいて左値または右値として転送する。その実装は以下のようになる:

template <typename T>
struct my_remove_reference {
    using type = T;
};

template <typename T>
struct my_remove_reference<T&> {
    using type = T;
};

template <typename T>
struct my_remove_reference<T&&> {
    using type = T;
};

template <typename T>
constexpr T&& my_forward(
    typename my_remove_reference<T>::type& arg) noexcept {
    return static_cast<T&&>(arg);
}

template <typename T>
constexpr T&& my_forward(
    typename my_remove_reference<T>::type&& arg) noexcept {
    static_assert(!std::is_lvalue_reference_v<T>,
                  "Cannot forward an rvalue as an lvalue.");
    return static_cast<T&&>(arg);
}

my_forward は、テンプレートパラメータ T の型情報を利用して、元の引数が左値か右値かを再現する。これは主にユニバーサルリファレンス(T&&)を受け取るテンプレート関数内で使用される。

以下のテストコードは、これらの自作関数の動作を検証するものである:

#include <iostream>

void process(int&) {
    std::cout << "lvalue reference\n";
}

void process(int&&) {
    std::cout << "rvalue reference\n";
}

template <typename T>
void testForward(T&& arg) {
    process(my_forward<T>(arg));
}

int main() {
    int x = 100;
    testForward(1);           // 右辺値 → rvalue reference
    testForward(x);           // 左辺値 → lvalue reference
    testForward(my_move(x));  // move後 → rvalue reference
}

実行結果は以下の通り:

Rvalue reference
lvalue reference
Rvalue reference

この結果から、my_forward が引数の値カテゴリを正しく維持し、my_move が左辺値を右辺値に変換していることが確認できる。

タグ: C++ move semantics perfect forwarding rvalue reference universal reference

7月14日 21:52 投稿