std::reference_wrapper,构造函数实现解释
std::reference_wrapper, constructor implementation explaination
一直在努力理解std::reference_wrapper
、from here的实现,具体如下:
namespace detail {
template <class T> constexpr T& FUN(T& t) noexcept { return t; }
template <class T> void FUN(T&&) = delete;
}
template <class T>
class reference_wrapper {
public:
// types
typedef T type;
// construct/copy/destroy
template <class U, class = decltype(
detail::FUN<T>(std::declval<U>()),
std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>()
)>
constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
: _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
reference_wrapper(const reference_wrapper&) noexcept = default;
// assignment
reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
// access
constexpr operator T& () const noexcept { return *_ptr; }
constexpr T& get() const noexcept { return *_ptr; }
template< class... ArgTypes >
constexpr std::invoke_result_t<T&, ArgTypes...>
operator() ( ArgTypes&&... args ) const {
return std::invoke(get(), std::forward<ArgTypes>(args)...);
}
private:
T* _ptr;
};
虽然 std::reference_wrapper 的实现已经被讨论 and ,但是它的 none 讨论了我感到困惑的构造函数实现。我的困惑是:
1.) 构造函数是一个模板函数,采用不同于模板 class 参数 T
的类型参数 (U
)。我已经看到 class 的成员函数是模板函数,并且取决于不同的类型参数,然后是模板的类型参数 class,但我想不出它在这里是如何工作的。有一个相关问题 here,但我无法将其与我的困惑联系起来。
2.)我看到构造函数中的第二个类型参数进一步用于 sfinae 一些东西,但我不明白 detail::FUN<T>(std::declval<U>())
是如何计算的。
有人可以解释一下吗?
编辑:这是从 microsoft.docs 添加的示例。的一个片段
例如:
int i = 1;
std::reference_wrapper<int> rwi(i); // A.1
rwi.get() = -1;
std::cout << "i = " << i << std::endl; //Prints -1
随着 reference_wrapper 的实现,从 A.1
开始,reference_wrapper 的构造函数是如何调用的?假设 detail::FUN<T>(std::declval<U>()
将用 detail::FUN<T>(std::declval<int>()
调用,应该是替换失败,因为 deleted
过载(假设 std::declval<int>
将被读取为对 int 的右值引用)。我在这里错过了什么?
当您想要“转发引用”的行为时可以使用这种技术,U&&
在这种情况下,但同时限制可以绑定到它的内容。
T
的推导由下面提供的推导指南提供帮助。 detail::FUN<T>(std::declval<U>())
用于确保当 U
被推断为右值引用时禁用构造函数,方法是选择已删除的重载并生成无效表达式。如果 U
是另一个引用包装器,它也会被禁用,在这种情况下,应该选择复制构造函数。
以下是有效和无效 reference_wrapper
的几个示例:
int i = 1;
// OK: FUN<int>(std::declval<int&>()) is valid
std::reference_wrapper<int> rwi(i);
// error: forming pointer to reference
std::reference_wrapper<int&> rwi2(i);
// OK, uses deduction guide to find T = int
std::reference_wrapper rwi3(i);
std::reference_wrapper rwi4(++i);
// error: cannot deduce T, since there is no deduction guide for
// rvalue reference to T
std::reference_wrapper rwi5(std::move(i));
// error: substitution failure of FUN<int>(int&&)
std::reference_wrapper<int> rwi6(std::move(i));
std::reference_wrapper<int> rwi7(i++);
std::reference_wrapper<int> rwi8(i + i);
std::reference_wrapper<int> rwi9(2);
如您所见,对已删除 FUN<T>(T&&)
的调用仅在最后 4 种情况下起作用:当您明确指定 T
,但尝试从右值构造时。
一直在努力理解std::reference_wrapper
、from here的实现,具体如下:
namespace detail {
template <class T> constexpr T& FUN(T& t) noexcept { return t; }
template <class T> void FUN(T&&) = delete;
}
template <class T>
class reference_wrapper {
public:
// types
typedef T type;
// construct/copy/destroy
template <class U, class = decltype(
detail::FUN<T>(std::declval<U>()),
std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>()
)>
constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
: _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
reference_wrapper(const reference_wrapper&) noexcept = default;
// assignment
reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
// access
constexpr operator T& () const noexcept { return *_ptr; }
constexpr T& get() const noexcept { return *_ptr; }
template< class... ArgTypes >
constexpr std::invoke_result_t<T&, ArgTypes...>
operator() ( ArgTypes&&... args ) const {
return std::invoke(get(), std::forward<ArgTypes>(args)...);
}
private:
T* _ptr;
};
虽然 std::reference_wrapper 的实现已经被讨论 T
的类型参数 (U
)。我已经看到 class 的成员函数是模板函数,并且取决于不同的类型参数,然后是模板的类型参数 class,但我想不出它在这里是如何工作的。有一个相关问题 here,但我无法将其与我的困惑联系起来。
2.)我看到构造函数中的第二个类型参数进一步用于 sfinae 一些东西,但我不明白 detail::FUN<T>(std::declval<U>())
是如何计算的。
有人可以解释一下吗?
编辑:这是从 microsoft.docs 添加的示例。的一个片段 例如:
int i = 1;
std::reference_wrapper<int> rwi(i); // A.1
rwi.get() = -1;
std::cout << "i = " << i << std::endl; //Prints -1
随着 reference_wrapper 的实现,从 A.1
开始,reference_wrapper 的构造函数是如何调用的?假设 detail::FUN<T>(std::declval<U>()
将用 detail::FUN<T>(std::declval<int>()
调用,应该是替换失败,因为 deleted
过载(假设 std::declval<int>
将被读取为对 int 的右值引用)。我在这里错过了什么?
当您想要“转发引用”的行为时可以使用这种技术,U&&
在这种情况下,但同时限制可以绑定到它的内容。
T
的推导由下面提供的推导指南提供帮助。 detail::FUN<T>(std::declval<U>())
用于确保当 U
被推断为右值引用时禁用构造函数,方法是选择已删除的重载并生成无效表达式。如果 U
是另一个引用包装器,它也会被禁用,在这种情况下,应该选择复制构造函数。
以下是有效和无效 reference_wrapper
的几个示例:
int i = 1;
// OK: FUN<int>(std::declval<int&>()) is valid
std::reference_wrapper<int> rwi(i);
// error: forming pointer to reference
std::reference_wrapper<int&> rwi2(i);
// OK, uses deduction guide to find T = int
std::reference_wrapper rwi3(i);
std::reference_wrapper rwi4(++i);
// error: cannot deduce T, since there is no deduction guide for
// rvalue reference to T
std::reference_wrapper rwi5(std::move(i));
// error: substitution failure of FUN<int>(int&&)
std::reference_wrapper<int> rwi6(std::move(i));
std::reference_wrapper<int> rwi7(i++);
std::reference_wrapper<int> rwi8(i + i);
std::reference_wrapper<int> rwi9(2);
如您所见,对已删除 FUN<T>(T&&)
的调用仅在最后 4 种情况下起作用:当您明确指定 T
,但尝试从右值构造时。