为什么 std::addressof 的正确实现需要编译器支持?

cpp*_*cpp 4 c++ gcc llvm visual-c++ c++11

从https://en.cppreference.com/w/cpp/memory/addressofstd::addressof上的可能实现来看,它指出“std::addressof 的正确实现需要编译器支持”。为什么会这样呢?

我在https://godbolt.org/z/vnzbs9aTG上尝试了该实现,它按预期工作。

#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;
}
Run Code Online (Sandbox Code Playgroud)

use*_*522 5

std::addressof应该可以在常量表达式中使用。例如

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

constexpr int j = test();
Run Code Online (Sandbox Code Playgroud)

应该是有效的,但不会与您的实现一起使用。添加constexpr您的实现也无济于事,因为计算reinterpret_cast总是会取消表达式作为常量表达式的资格。

此外,您还缺少已删除的const右值重载,以防止获取右值的地址。


上述内容自 C++17 起适用。如果您要求使用标记的 C++11,那么是的,这是 C++11 的有效实现。如果您浏览 cppreference 页面上提供的标准库实现链接,您还会看到它们在 C++17 之前使用了建议的实现(的微小变体)。

  • @cpp 通过 git Blame 查看这些行的历史记录,你会发现提交 https://github.com/gcc-mirror/gcc/commit/9e023e3321886e0ba1ea7b25c7ef70e50c267963。C++17 更改之前的先前版本使用问题中的实现,但不需要非对象类型的特殊情况,因为 GCC 支持将函数指针转换为对象指针。 (2认同)