如何编写正向函数模板?
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';
}
- 不知道
k
怎么了?为什么我可以将右值作为左值传递? (fwd_<int&>(7)
)?
我确定左值引用绑定到函数模板参数;不是通过的参数。
我也确信该表达式会产生未定义的行为,因为该参数在 fwd_
returns.
时被销毁
我已经尝试过并更改了优化级别,因此由于 UB,我得到了不同的值。
我的想法对吗?如果是的话,我怎么能写一个干净和正确的版本来模仿库一 std::forward
?谢谢!
I don't know what happened to k? and how come I can pass an r-value as an l-value? (fwd_<int&>(7))
?
是的,这很危险,因为 T
是 int&
和 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);
}
我想了解更多 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';
}
- 不知道
k
怎么了?为什么我可以将右值作为左值传递? (fwd_<int&>(7)
)?
我确定左值引用绑定到函数模板参数;不是通过的参数。
我也确信该表达式会产生未定义的行为,因为该参数在 fwd_
returns.
我已经尝试过并更改了优化级别,因此由于 UB,我得到了不同的值。
我的想法对吗?如果是的话,我怎么能写一个干净和正确的版本来模仿库一
std::forward
?谢谢!
I don't know what happened to k? and how come I can pass an r-value as an l-value?
(fwd_<int&>(7))
?
是的,这很危险,因为 T
是 int&
和 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);
}