4

左辺値または右辺値の引数をパラメーターとして他の関数に効率的に渡すことができるように、テンプレート化された関数での完全な転送について広範な議論があります。

ただし、完全なリターンまたは同等の完全なパススルーに関する議論を見つけることができません。(関連する質問完全なパススルーは、これに完全には対応していません。)

範囲を変更し、変更された範囲を返す関数の場合を考えてみましょう。左辺値と右辺値の引数のケースに効率的に対処するには、2 つの別個の関数が必要になります。

// Given a reference to an lvalue range, return a reference to the same modified range.
// (There is no allocation or move.)
template<typename T> T& sortr(T& r) {
    std::sort(std::begin(r),std::end(r));
    return r;
}

// Given an rvalue range, return the same range via (hopefully) a move construction.
template<typename T> T sortr(T&& r) {
    std::sort(std::begin(r),std::end(r));
    return std::move(r);
}

もちろん、両方の定義を含めると、2 番目の定義も左辺値参照に一致するため、あいまいなエラーが発生します。

動機付けとなる例 (およびテストの使用) は次のとおりです。

#include <iostream>
#include <vector>
#include <algorithm>

std::ostream& operator<<(std::ostream& os, const std::vector<int>& v) {
    os << "["; for (int i : v) { os << " " << i; } os << " ]\n"; return os;
}

int main() {
    std::vector<int> c1{3,4,2,1};
    std::cerr << sortr(c1) << sortr(std::vector<int>({7,6,5,8}));
}

sortr単一の定義を使用して の両方のバージョンを定義できますtemplate<typename T>か?

課題は、戻り値の型を as として宣言すると、T&&(テンプレート マッチング後に)T&&またはT&戻り値の型になるだけであり、 ではありませんT

戻り値の型でメタプログラミングを使用して適切なテンプレート関数を定義することは可能ですか? 次のようなもの:

template<typename T> auto sortr(T&& r) ->
    typename std::conditional<std::is_lvalue_reference<T>::value, T&, T>::type
{
    std::sort(std::begin(r),std::end(r));
    return std::forward<T>(r);
}

これは機能しているようですが、安全で賢明かどうかはわかりません。どんなガイダンスも大歓迎です。

4

1 に答える 1