转发参考:给定T&&和T&当给予T&

时间:2018-03-03 17:58:32

标签: c++ c++11

考虑一个类A,我该如何编写一个与

具有相同行为的模板
A& pretty(A& x)
{
    /* make x pretty */
    return x;
}

A pretty(A&& x)
{
    /* make x pretty */
    return x;
}

知道我想:

  1. 以完全相同的方式修改参数(x),与参数是左值引用还是左值引用无关(实际上,两个部分/* make x pretty */是相同的)因此具有单一功能;

  2. 避免不必要的复制;

  3. 能够使用该函数修改变量;

  4. 能够“管道”函数调用,无论参数是rvalue还是左值。

  5. 作为3.和4的示例,请考虑以下用例:

    void read_A(const A& x) { /* ... */ }
    void take_A(A&& x)      { /* ... */ }
    
    A x();
    read_A(pretty(x));
    take_A(pretty(A()));
    

    我的想法是利用转发引用,同时将允许的参数限制为A的引用。但是返回类型呢?

    template<typename T>
    std::enable_if_t<std::is_same<T, A>::value>
    /*???*/ pretty(T&& x)
    {
        /* make x pretty */
        return x; //?
    }
    

2 个答案:

答案 0 :(得分:3)

为什么不简单地写

#include <iostream>

template <class T>
T somefunc(T&& a) {
  /* do something with a */
  std::cout << __PRETTY_FUNCTION__ << '\n';
  return std::forward<T>(a);
}

int main(int argc, char* argv[]) {
  int a = 5;

  somefunc(a);
  somefunc(5);

  return 0;
}

将返回

T somefunc(T &&) [T = int &]
T somefunc(T &&) [T = int]

如您所见,这些功能具有您想要的签名。在第一次通话中,T获得int &,因此获得int &的返回值。在第二个中,你有T = int = int &&,这也是你想要的。

编辑。顺便说一句,您最初考虑应用std::is_same来禁用A以外的类型的重载解析似乎也是错误的。根据{{​​3}},

  

如果TU使用相同的const-volatile资格来命名相同的类型,则提供等于true的成员常量值。否则值为false

因此,您可能希望使用decay或至少remove_cvremove_reference的组合来应用您想要的逻辑。下面是上面代码的修改版本,现在包含重载决策启用程序。

#include <iostream>
#include <type_traits>

template <class T> T somefunc(T &&a) {
  /* do something with a */
  std::cout << __PRETTY_FUNCTION__ << '\n';
  return std::forward<T>(a);
}

template <class T, typename std::enable_if<
                       std::is_same<typename std::decay<T>::type, float>::value,
                       int>::type = 0>
T onlyfloat_correct(T &&a) {
  /* do something with a */
  std::cout << __PRETTY_FUNCTION__ << '\n';
  return std::forward<T>(a);
}

template <class T,
          typename std::enable_if<std::is_same<T, float>::value, int>::type = 0>
T onlyfloat_wrong(T &&a) {
  /* do something with a */
  std::cout << __PRETTY_FUNCTION__ << '\n';
  return std::forward<T>(a);
}

int main(int argc, char *argv[]) {
  int a = 5;
  const float b = 5;

  somefunc(a);
  somefunc(5);

  onlyfloat_correct(b);
  // onlyfloat_wrong(b);

  return 0;
}

答案 1 :(得分:0)

您根本不需要模板。您可以利用rvalue引用是左值引用过载中的左值全部调用pretty这一事实,因此您只需要在左值过载中编写make x pretty逻辑。看起来像是

A& pretty(A& x)
{
    /* make x pretty */
    return x;
}

A pretty(A&& x)
{
    return std::move(pretty(x));
}