如何编写正向函数模板?

How to write a forward function template?

我想了解更多 std::forward 的工作原理以及显式模板参数和模板参数推导如何与转发引用一起工作,我试过这个例子:

template <typename T>
T&& fwd_(typename std::remove_reference<T>::type& arg){
    std::cout << "fwd_(type&)\n";
    return static_cast<T&&>(arg);
}

template <typename T>
T&& fwd_(typename std::remove_reference<T>::type&& arg){
    std::cout << "fwd_(type&&)\n";
    ++arg;
    return static_cast<T&&>(arg);
}

int main(){

    int&& l = fwd_<int>(5);
    int&& m = fwd_<int&&>(7);
    int& j = fwd_<int&>(m);
    int& k = fwd_<int&>(7); // UB?
    std::cout << k << std::endl;

  std::cout << '\n';
}

我确定左值引用绑定到函数模板参数;不是通过的参数。

我也确信该表达式会产生未定义的行为,因为该参数在 fwd_ returns.

时被销毁

I don't know what happened to k? and how come I can pass an r-value as an l-value? (fwd_<int&>(7))?

是的,这很危险,因为 Tint& 和 return 值 T&&,作为 reference collapsing 的结果我们得到 int& &&int&,即你最终 return 引用一个临时的,它不是生命延长的,因此在完整表达式的末尾销毁临时后导致 UB(;).

出于这个原因,C++ 标准明确地 excludes 这个用法来自 std::forward:

template <class T> constexpr T&& forward(remove_reference_t<T>& t) noexcept;
template <class T> constexpr T&& forward(remove_reference_t<T>&& t) noexcept;
. . .

3 Remarks: If the second form is instantiated with an lvalue reference type, the program is ill-formed.

并且 libstdc++ 例如在这种情况下有一个 assertion 提前失败:

  template<typename _Tp>
    constexpr _Tp&&
    forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
    {
      static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
            " substituting _Tp is an lvalue reference type");
      return static_cast<_Tp&&>(__t);
    }