template< class Ptr >
constexpr auto to_address(const Ptr& p) noexcept;
template< class T >
constexpr T* to_address(T* p) noexcept;
to_address
从缀饰指针获得裸指针(pointer_to 的反函数)
获得 p 所指向的地址,而不形成到被指向者的引用:
参数:p - 缀饰或裸指针
注释: 即使在 p 引用的存储中无已构造的对象时,也能使用 std::to_address ,该情况下不能用 std::addressof(*p) ,因为无可绑定 std::addressof 参数的合法对象。1 2
// https://zh.cppreference.com/w/cpp/memory/to_address
// https://zh.cppreference.com/w/cpp/memory/pointer_traits/to_address
//// 可能实现
//template
//constexpr T* to_address(T* p) noexcept
//{
// static_assert(!std::is_function_v);
// return p;
//}
//
//template
//constexpr auto to_address(const T& p) noexcept
//{
// if constexpr (requires{ std::pointer_traits::to_address(p); }) {
// return std::pointer_traits::to_address(p);
// }
// else {
// return std::to_address(p.operator->());
// }
//}
template
auto allocator_new(A& a)
{
auto p = a.allocate(1);
try {
std::allocator_traits::construct(a, std::to_address(p));
}
catch (...) {
a.deallocate(p, 1);
throw;
}
return p;
}
template
void allocator_delete(A& a, typename std::allocator_traits::pointer p)
{
std::allocator_traits::destroy(a, std::to_address(p));
a.deallocate(p, 1);
}
void test_to_address01() {
std::allocator a;
auto p = allocator_new(a);
allocator_delete(a, p);
}
glenfe/to_address 3
// https://github.com/glenfe/to_address/blob/master/test/to_address_test.cpp
template
class P1 {
public:
explicit P1(T* p)
: p_(p) { }
T* operator->() const noexcept {
return p_;
}
private:
T* p_;
};
template
class P2 {
public:
explicit P2(T* p)
: p_(p) { }
P1 operator->() const noexcept {
return p_;
}
private:
P1 p_;
};
template
class P3 {
public:
explicit P3(T* p)
: p_(p) { }
T* get() const noexcept {
return p_;
}
private:
T* p_;
};
namespace std {
template
struct pointer_traits > {
static T* to_address(const P3& p) noexcept {
return p.get();
}
};
} // std
template
class P4 {
public:
explicit P4(T* p)
: p_(p) { }
T* operator->() const noexcept {
return nullptr;
}
T* get() const noexcept {
return p_;
}
private:
int* p_;
};
namespace std {
template
struct pointer_traits > {
static T* to_address(const P4& p) noexcept {
return p.get();
}
};
} // std
void test_to_address02() {
int i = 0;
assert(std::to_address(&i) == &i);
int* p = &i;
assert(std::to_address(p) == &i);
P1 p1(&i);
assert(std::to_address(p1) == &i);
P2 p2(&i);
assert(std::to_address(p2) == &i);
P3 p3(&i);
assert(std::to_address(p3) == &i);
P4 p4(&i);
assert(std::to_address(p4) == &i);
}
若类型 T 为引用类型,则提供成员 type ,它是移除了其最顶层 cv 限定符的 T 所引用的类型。否则 type 为移除最顶层 cv 限定符的 T 。
添加 remove_cvref 的特化的程序行为未定义。4
#include
#include
void test_remove_cvref() {
std::cout << std::boolalpha
<< std::is_same_v, int> << '\n'
<< std::is_same_v, int> << '\n'
<< std::is_same_v, int> << '\n'
<< std::is_same_v, int> << '\n'
<< std::is_same_v, int[2]> << '\n'
<< std::is_same_v, int[2]> << '\n'
<< std::is_same_v, int(int)> << '\n';
}
template
constexpr /*unspecified*/ bind_front( F&& f, Args&&... args );
函数模板 bind_front 为 f 生成转发调用包装。调用此包装等价于绑定首 sizeof…(Args) 个参数到 args 再调用 f 。5
换言之 std::bind_front(f, bound_args…)(call_args…) 等价于 std::invoke(f, bound_args…, call_args…) 。
注释:有意令此函数取代 std::bind 。不同于 std::bind ,它不支持任意参数重排,而且不特别处理嵌套的 bind 表达式或 std::reference_wrapper 。另一方面,它注重调用包装对象的值类别,并传播底层调用运算符的异常规定。
如 std::invoke 中描述,调用指向非静态成员函数指针或指向非静态数据成员指针时,首参数必须是到要访问其成员的对象的引用或指针(可以包含智能指针,如 std::shared_ptr 与 std::unique_ptr )。
复制或移动给 std::bind_front 的参数,而决不按引用传递,除非用 std::ref 或 std::cref 包装它们。
#include
#include
int minus(int a, int b) {
return a - b;
}
void test_bind_front() {
auto fifty_minus = std::bind_front(&minus, 50);
std::cout << fifty_minus(3);
}
https://github.com/5455945/cpp_demo/blob/master/C%2B%2B20/to_address/to_address.cpp
to_address ↩︎
std::pointer_traits::to_address ↩︎
glenfe/to_address ↩︎
remove_cvref ↩︎
bind_front ↩︎