std::addressof
| Определено в заголовочном файле <memory>
|
||
template< class T > T* addressof( T& arg ) noexcept; |
(1) | (начиная с C++11) (constexpr начиная с C++17) |
template< class T > const T* addressof( const T&& ) = delete; |
(2) | (начиная с C++11) |
arg даже при наличии перегруженного operator&.const.|
Выражение |
(начиная с C++17) |
Параметры
| arg | — | левосторонний объект или функция |
Возвращаемое значение
Указатель на arg.
Возможная реализация
Приведённая ниже реализация не является constexpr, потому что reinterpret_cast нельзя использовать в константном выражении. Необходима поддержка компилятора (смотрите ниже).
// std::remove_reference необходим для явного указания аргументов шаблона
// например addressof<int&> и addressof<int&&> должны вести себя так же,
// как и addressof<int>
// перегрузка для объектных типов
template<class T>
typename std::enable_if<std::is_object<
typename std::remove_reference<T>::type>::value, T*>::type addressof(T& arg) noexcept
{
return reinterpret_cast<T*>(
&const_cast<char&>(
reinterpret_cast<const volatile char&>(arg)));
}
// перегрузка для функциональных типов
template<class T>
typename std::enable_if<!std::is_object<
typename std::remove_reference<T>::type>::value, T*>::type addressof(T& arg) noexcept
{
return &arg;
}
|
Для правильной реализации этой функции требуется поддержка компилятора: GNU libstdc++, LLVM libc++, Microsoft STL.
Примечание
| Макрос Тестирования функциональности | Значение | Стандарт | Функциональность |
|---|---|---|---|
__cpp_lib_addressof_constexpr |
201603L |
(C++17) | constexpr std::addressof
|
constexpr для addressof добавляется через LWG2296, а MSVC STL применяет изменение в режиме C++14 в качестве отчёта о дефекте.
Пример
operator& может быть перегружен для класса-оболочки указателя, чтобы получить указатель на указатель:
#include <iostream>
#include <memory>
template<class T>
struct Ptr
{
T* pad; // добавляем pad, чтобы показать разницу между 'this' и 'data'
T* data;
Ptr(T* arg) : pad(nullptr), data(arg)
{
std::cout << "this конструктора = " << this << '\n';
}
~Ptr() { delete data; }
T** operator&() { return &data; }
};
template<class T>
void f(Ptr<T>* p)
{
std::cout << "перегрузка Ptr вызывается с помощью p = " << p << '\n';
}
void f(int** p)
{
std::cout << "перегрузка int** вызывается с помощью p = " << p << '\n';
}
int main()
{
Ptr<int> p(new int(42));
f(&p); // вызывает перегрузку int**
f(std::addressof(p)); // вызывает перегрузку Ptr<int>*, (= this)
}
Возможный вывод:
this конструктора = 0x7fff59ae6e88
перегрузка int** вызывается с помощью p = 0x7fff59ae6e90
перегрузка Ptr вызывается с помощью p = 0x7fff59ae6e88
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 2598 | C++11 | std::addressof<const T> может принимать адреса rvalue
|
запрещено удалённой перегрузкой |
Смотрите также
| аллокатор по умолчанию (шаблон класса) | |
[static] |
получает разыменованный указатель на свой аргумент (public static функция-элемент std::pointer_traits)
|