3

From possible implementation of std::addressof on https://en.cppreference.com/w/cpp/memory/addressof, it states that "correct implementation of std::addressof require compiler support". Why is it the case?

I tried out the implementation on https://godbolt.org/z/vnzbs9aTG and it worked as expected.

#include <iostream>
#include <string>
#include <type_traits>

template<class T>
typename std::enable_if<std::is_object<T>::value, T*>::type addressof_impl(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<T>::value, T*>::type addressof_impl(T& arg) noexcept
{
    return &arg;
}

struct Student {
    std::string name{};
    int age{};
};

int main() {
    Student s;
    std::cout << addressof_impl(s);
    return EXIT_SUCCESS;
}
cpp
  • 265
  • 1
  • 6
  • Taking the address of something using the address-of operator `&` is a run-time operation. The `std::addressof` function is **`constexpr`** and therefore means the address can be taken at compile-time. The address-of operator `&` can't do that, to get the address at compile-time requires compiler support. – Some programmer dude Jul 01 '23 at 12:20
  • 3
    Always be careful, "it seems to work (on my machine)" is not the same as "it is correct c++" (though admittedly even with a lot of experience it is hard to know the difference sometimes) – Pepijn Kramer Jul 01 '23 at 12:27

1 Answers1

5

std::addressof is supposed to be usable inside constant expressions. For example

constexpr int test() {
    int x;
    *std::addressof(x) = 0;
    return x;
}

constexpr int j = test();

should be valid, but won't be with your implementation. Adding constexpr on your implementation won't help either, because evaluating reinterpret_cast always disqualifies an expression from being a constant expression.

Also, you are missing the deleted const rvalue overload to prevent taking the address of rvalues.


The above applies since C++17. If you are asking for C++11 as you tagged, then yes, that's a valid implementation for C++11. If you go through the standard library implementation links provided on the cppreference page, you'll also see that they used (minor variations of) the suggested implementation before C++17.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Sorry @user17732522 I accidentally added the incomplete comment which I have removed already. I was trying to ask regarding what you said `If you go through the standard library implementation ...`, I did go through the standard library implementation links on the cppreference page, ie https://github.com/gcc-mirror/gcc/blob/b8806796ec64585de39ca6ee3b7b30cc08f27d62/libstdc++-v3/include/bits/move.h#L47-L50 I couldn't see they used minor variation of the suggested implementation. I saw they used __builtin_addressof to support constexpr as you explained. Would you point me to it please? – cpp Jul 01 '23 at 13:55
  • 2
    @cpp Look into the history of these lines via git blame and you'll find commit https://github.com/gcc-mirror/gcc/commit/9e023e3321886e0ba1ea7b25c7ef70e50c267963. The previous version before the change for C++17 uses the implementation from the question, except that the special case for non-object types isn't required because GCC supports casting function pointers to object pointers. – user17732522 Jul 01 '23 at 14:02
  • Appreciate @user17732522 for clarifying my doubt in https://en.cppreference.com/w/cpp/memory/addressof as well. – cpp Jul 02 '23 at 03:35