【问题标题】:If std::addressof is a readable version of &. What is a readable version of *&?如果 std::addressof 是 & 的可读版本。 *& 的可读版本是什么?
【发布时间】:2017-12-20 18:59:37
【问题描述】:

*&x

使用c++11,我们可以写成

* std::addressof(x)

但是,这个表达式有更易读的版本吗?

constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e; 
    // a.k.a. Clockwise-Rotated Endian which allocates like
    // char[8] = { n,a,i,d,n,e,\0,\0 }

constexpr auto& arr = 
    reinterpret_cast<const std::array<char,8> &>
        (*std::addressof(lil_endian) );

int main()
{
    const auto str = std::string(arr.crbegin()+2, arr.crend() );

    std::cout << str << '\n'
              << str.size() << '\n' << '\n';
    for (const auto ch : str) {
        std::cout << ch << " : " << std::hex << (unsigned int) ch << '\n';
    }

}


endian
6

e : 65
n : 6e
d : 64
i : 69
a : 61
n : 6e

godbolt.org/g/9StHsE

wandbox.org/permlink/ZzQ38IlDficO5UOi

【问题讨论】:

  • 通过arr 访问lil_endian 是未定义的行为。另外,你想做什么? *&amp;x 用于“普通类型”是一个 noop
  • @Barry 我不知道如何解释这一点,但请尝试在上面的上帝螺栓链接上将 *&amp;x 替换为 x
  • & 和 addressof 通常不相等
  • 你觉得std::addressof更多可读吗?
  • @sandthorn 您的上帝螺栓链接使用 lil_endian*&amp;lil_endian*std::addressof(lil_endian) 生成完全相同的程序集。

标签: c++ c++11 address-operator


【解决方案1】:

* std::addressof(x)

但是,这个表达式有更易读的版本吗?

x

【讨论】:

  • 虽然与病理类不完全等价。
  • 我不能在上面的示例代码中将*std::addressof(lil_endian) 替换为lil_endian。你可以在godbolt链接上自己试试。
  • @sandthorn:这是一件好事,因为您拥有的是未定义的行为
  • @sandthorn 这是未定义的行为,不需要诊断,因为检测已定义的内容而不是在运行时(在一般情况下)很难停止。
  • @sandthorn:不幸的是,你不能可靠地这样做。
【解决方案2】:

维托里奥·罗密欧给你第二个问题的答案。

第一个假设是错误的:“addressof&amp; 的可读版本”。 addressof 用于获取对象的地址,即使其类类型具有重载的operator &amp;

【讨论】:

  • @remy-lebeau 这意味着当需要地址时,std::addressof 现在比&amp; 更受欢迎?
  • @sandthorn:仅当对象的类型具有不返回对象真实地址的覆盖 operator&amp; 时。例如,这在非 STL 智能指针类中并不少见。
  • @sandthron 许多库确实使用addressof,甚至是STL(另见std::pointer_traits::pointer_to)。我不。我更喜欢拒绝任何operator &amp; 过载的库。如果犯了这样的错误(重载此运算符),您可能会遇到更多错误。要做出决定,您需要明确的指示符:operator &amp; 重载 => 库被拒绝。
【解决方案3】:

目前尚不清楚您要做什么以及为什么使用constexpr

但是你的代码有几个问题:

但是,您可以通过在非constexpr 上下文中使用const char* 别名来解决这两个问题。所以以下是合法的:

#include <iostream>

constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e; 

int main()
{
    auto arr = reinterpret_cast<const char*>(&lil_endian);
    for (size_t i = 0; i < sizeof(lil_endian); ++i) {
        std::cout << arr[i] << " : " << std::hex << (unsigned int) arr[i] << '\n';
    }

}

顺便说一句,*&amp; 的需求也消失了。

DEMO

== 编辑 ==

如果您只需要以通用方式获取变量的大小,只需在函数模板中使用sizeof。例如:

#include <cstdio>
#include <cstdint>

constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e; 
constexpr uint32_t lil_endian32 = 0x65'6e'64'69;

template<typename T>
void printIt(const T& it)
{
    auto arr = reinterpret_cast<const char*>(&it);
    for (size_t i = 0; i < sizeof(it); ++i) {
        putchar(arr[i]);
    }
}

int main()
{
    printIt(lil_endian);
    printIt(lil_endian32);
}

DEMO

【讨论】:

  • (1) constexpr :现在我知道不允许重新解释 (2) 我正在尝试使 arr 具有 lil_endian 的大小,仅此而已。但是我想知道reinterpret_cast&lt;const char*&gt; 是否“合法”。 auto&amp; arr = reinterpret_cast&lt;char (&amp;) [8]&gt;(lil_endian); 怎么样?我们也访问 char 对吗?
  • 原来的问题现在已经被很多人很好地回答了。也许我应该将这个“严格别名”主题作为另一个问题。无论如何,感谢@rustyx 提供的函数模板。
猜你喜欢
  • 1970-01-01
  • 2017-09-15
  • 2019-12-14
  • 2016-04-09
  • 1970-01-01
  • 2017-02-16
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多