4

对模板函数中的完美转发进行了广泛的讨论,以允许有效地将左值或右值参数作为参数传递给其他函数。

但是,我找不到关于完美回报或等效完美传递的讨论。(相关问题完美传递并没有完全解决这个问题。)

考虑修改范围并应返回修改后范围的函数的情况。我们需要两个单独的函数来有效地处理左值和右值参数的情况:

// 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);
}

当然,包含这两个定义会导致歧义错误,因为第二个定义也匹配左值引用。

一个激励示例(和测试使用)如下:

#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>定义的两个版本吗?

挑战在于,将返回类型声明为T&&(在模板匹配之后)只会导致 aT&&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

7

您需要使用通用参考。在这种情况下,您可以返回 just T,但您需要将模板函数更改为此:

template<typename T> T sortr(T && r) {
    std::sort(std::begin(r),std::end(r));
    return std::forward<T>(r);
}

完整示例:

#include <iostream>
#include <utility>
#include <type_traits>
#include <vector>
#include <algorithm>

template<typename T> T sortr(T && r) {
    std::sort(std::begin(r),std::end(r));
    return std::forward<T>(r);
}

std::vector<int> foo()
{
  return std::vector<int>(5,2);
}

void test( std::vector<int> & )
{
  std::cout<<"lvalue" << std::endl;
}
void test( std::vector<int> && )
{
  std::cout<<"rvalue" << std::endl;
}

int main()
{
  std::vector<int> v(1,6);

  test( sortr( foo() ) );
  test( sortr( v ) );
}

如果您不知道什么是通用参考,请查看Scott Meyers 的这篇演讲

于 2013-09-19T18:28:29.633 回答