【问题标题】:add_lvalue_reference implementation exampleadd_lvalue_reference 实现示例
【发布时间】:2019-12-22 17:41:24
【问题描述】:

cppreference上查找std::add_lvalue_reference时,可以看到如下实现示例:

namespace detail {

template <class T>
struct type_identity { using type = T; }; // or use std::type_identity (since C++20)

template <class T>
auto try_add_lvalue_reference(int) -> type_identity<T&>;
template <class T>
auto try_add_lvalue_reference(...) -> type_identity<T>;

} // namespace detail

template <class T>
struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {};

为什么需要第二个try_add_lvalue_reference?在什么情况下会调用它来代替第一个?

【问题讨论】:

  • 不是一个完整的答案,但我认为这是在玩重载优先级,因此当需要添加引用时,第一个 try_add_lvalue_reference 将是首选。请注意,libc++ 实现是somewhat different
  • 我认为它只是表面上看起来不同。它使用隐藏在实现背后的函数a similar set
  • 你是对的......

标签: c++ c++11 std


【解决方案1】:

第二个重载处理cppreference 上给出的定义中的“否则”条件:

1) 如果 T 是没有 cv- 或 ref- 限定符或对象类型的函数类型,则提供成员 typedef 类型,即 T&。如果 T 是对某个类型 U 的右值引用,则类型为 U&。否则,类型为 T。

考虑例如:

using T = void() const; // Function type with const qualifier
using U = add_lvalue_reference<T>::type;

根据定义我们应该有U == T,但是如果我们没有第二个模板重载,那么这段代码会导致编译时错误:

不可能形成对 cv 或 ref 限定函数类型的引用,因此 try_add_lvalue_reference 的第一个模板重载被 SFINAE 淘汰。

如果只有这种过载,则调用 detail::try_add_lvalue_reference&lt;T&gt;(0) 会硬失败,因为没有可行的过载。

第二个重载不会尝试形成对 const 限定函数类型的引用,因此始终是可行的,如果第一个不是,将选择它,返回类型本身。

int... 参数确保两个重载都可以使用 int 参数调用,... 具有额外的好处,即它在重载解析中始终具有较低的优先级。因此,如果两个模板重载都是可行的,则将选择第一个来为类型提供尽可能添加的左值引用。

【讨论】:

  • 在尝试推导 try_add_lvalue_reference 辅助函数的行为时,我完全忽略了函数类型。这样就更清楚了。
猜你喜欢
  • 2019-11-16
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-16
  • 2016-08-23
  • 2017-03-13
  • 2011-01-16
相关资源
最近更新 更多