控制 T 绑定的引用类型
Control to what kind of references `T` binds
在考虑如何解决 std::min
dangling reference problem 时,我的一个想法是为将被删除的右值添加一个重载(实际上是 3 个 - 对于每个组合)。问题是 T&&
将是转发引用,而不是右值引用。
我想将此问题与 std::min
明确分开,使其更笼统。 std::min
可以作为一个例子,为什么你需要这样的东西。
让我们简化和概括问题:
// this has the same problem as `std::min`: if t binds to a temporary,
// and the result is assigned to `auto&`, the result is a dangled reference
template <class T>
const T& foo(const T& t)
{
return t;
}
// incorrect attempt to prevent foo from being called with a temporary argument
// `T&&` is a forwarding reference, not an rvalue reference
template <class T>
const T& foo(T&& t) = delete;
问题是:如何控制通用模板参数 T
可以绑定到哪种引用?它如何针对多个参数进行扩展(如 std::min
情况)?
你可以
template <typename T>
std::enable_if_t<std::is_rvalue_reference<T&&>::value>
foo(T&&) = delete;
对于 2 个参数,它变为:
template <typename T1, typename T2>
std::enable_if_t<
(std::is_rvalue_reference<T1&&>::value
|| std::is_rvalue_reference<T1&&>::value)
&& std::is_same<std::decay_t<T1>, std::decay_t<T2>>::value
>
foo(T1&&, T2&&) = delete;
Praetorian 的版本为:
template <class T> void foo(const T&&, const T&) = delete;
template <class T> void foo(const T&, const T&&) = delete;
template <class T> void foo(const T&&, const T&&) = delete;
鉴于您的代码,以下代码无法编译
int i = 0;
foo(i); // deleted function
之所以选择转发引用重载是因为匹配另一个需要const
资格。但是如果你写
int const i = 0;
foo(i); // perfectly fine
在这种情况下,重载采用 lvalue reference is selected。
因此,为了拒绝所有右值,delete
d 函数需要采用 T const&&
(这就是 std::ref
拒绝右值的做法)
template <class T>
const T& foo(const T& t)
{
return t;
}
template <class T>
const T& foo(T const&& t) = delete;
在考虑如何解决 std::min
dangling reference problem 时,我的一个想法是为将被删除的右值添加一个重载(实际上是 3 个 - 对于每个组合)。问题是 T&&
将是转发引用,而不是右值引用。
我想将此问题与 std::min
明确分开,使其更笼统。 std::min
可以作为一个例子,为什么你需要这样的东西。
让我们简化和概括问题:
// this has the same problem as `std::min`: if t binds to a temporary,
// and the result is assigned to `auto&`, the result is a dangled reference
template <class T>
const T& foo(const T& t)
{
return t;
}
// incorrect attempt to prevent foo from being called with a temporary argument
// `T&&` is a forwarding reference, not an rvalue reference
template <class T>
const T& foo(T&& t) = delete;
问题是:如何控制通用模板参数 T
可以绑定到哪种引用?它如何针对多个参数进行扩展(如 std::min
情况)?
你可以
template <typename T>
std::enable_if_t<std::is_rvalue_reference<T&&>::value>
foo(T&&) = delete;
对于 2 个参数,它变为:
template <typename T1, typename T2>
std::enable_if_t<
(std::is_rvalue_reference<T1&&>::value
|| std::is_rvalue_reference<T1&&>::value)
&& std::is_same<std::decay_t<T1>, std::decay_t<T2>>::value
>
foo(T1&&, T2&&) = delete;
Praetorian 的版本为:
template <class T> void foo(const T&&, const T&) = delete;
template <class T> void foo(const T&, const T&&) = delete;
template <class T> void foo(const T&&, const T&&) = delete;
鉴于您的代码,以下代码无法编译
int i = 0;
foo(i); // deleted function
之所以选择转发引用重载是因为匹配另一个需要const
资格。但是如果你写
int const i = 0;
foo(i); // perfectly fine
在这种情况下,重载采用 lvalue reference is selected。
因此,为了拒绝所有右值,delete
d 函数需要采用 T const&&
(这就是 std::ref
拒绝右值的做法)
template <class T>
const T& foo(const T& t)
{
return t;
}
template <class T>
const T& foo(T const&& t) = delete;