2

在考虑可以做些什么来解决std::min 悬空引用问题时,我想到的一个想法是为将被删除的右值添加一个重载(实际上每个组合为 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以防万一)?

4

2 回答 2

5

你可以做

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;
于 2016-01-27T18:10:34.840 回答
3

鉴于您的代码,以下无法编译

int i = 0;
foo(i);      // deleted function

选择转发引用过载的原因是因为匹配另一个需要const限定。但是如果你要写

int const i = 0;
foo(i);      // perfectly fine

在这种情况下,选择采用左值引用的重载。

因此,为了拒绝所有右值,deleted 函数需要采用 a 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;

现场演示

于 2016-01-27T18:23:29.050 回答