【问题标题】:What is this `(*(T*)nullptr)` old trick?这是什么 `(*(T*)nullptr)` 老把戏?
【发布时间】:2021-02-25 07:43:01
【问题描述】:

我刚刚阅读了Is declval<T>() the same as (*(T*)nullptr)? 并刚刚意识到我以前没有听说过(*(T*)nullptr) 技巧。如果我分析那个sn-p,它不会给我太多信息,除此之外(引用答案)

您可以在 decltype 中获取 T 的实例,而无需担心 T 的构造函数

而且发现的例子也很简单:

struct B {
    A a;
};
typedef decltype((*(B*)nullptr).a) T1;

那么,请有人向我解释一下这个 (*(T*)nullptr) 技巧是什么以及我为什么(以及如何)要使用它(除了上面的示例)?

编辑: decltype(B::a) 具有相同的含义 (https://gcc.godbolt.org/z/Pvjjza) 那么为什么要像这样过度复杂化呢?这个技巧的出现是否有任何历史意义(例如某些编译器不支持它或其他更有用的东西?)

【问题讨论】:

  • this thread 有帮助吗?接受的答案给出了为什么这样做/使用的一些背景。
  • @lubgr 谢谢,我也读过。我只是好奇这个奇怪的(*(T*)nullptr) 构造是否还有其他用途,或者这就是它被发明的唯一目的。

标签: c++ c++11


【解决方案1】:

nullptr 是一个空指针是的!

(B*)nullptr 将空指针转换为指向 B 类型对象的指针。

*(B*)nullptr 取消引用此指针以获取对 B 类型对象的引用

(*(B*)nullptr).a 访问此引用的成员“a”。

现在,如果您实际上是在正在运行的程序中执行此操作,您可能会崩溃您的程序或损坏您的数据,或者可能什么都不会发生,因为这是 undefined behaviour。无论如何,它是坏的和邪恶的,永远不应该在真正的程序中看到。

但是如果将整个表达式括在 decltype 中,您将获得表达式的返回类型,而不是执行表达式。

但是你可以使用declval,而不是写上面的丑陋。但只能在 decltype 中使用 declval

typedef decltype((*(B*)nullptr).a) BMemberA;

为您生成一个与B 类型的a 成员相同的类型。另一种更好的解决方案是写。

typedef decltype(declval<B>().a) BMemberA;

【讨论】:

  • 是的,但为什么过于复杂?仅使用:decltype(B::a) 就足够了。 gcc.godbolt.org/z/Pvjjza
  • 你问了这个问题:)。我刚刚向您解释了它们是如何基本相同的,并且您应该使用 declval。没有理由不使用 declval,除非可能在 declval 不可用的旧代码库中。但是你可以使用 boost::declval
  • 之所以有效,是因为B::a 是成员访问运算符如果您有一个B gcc.godbolt.org/z/7oTP1G 的实例。它有点深奥,一种用途是访问被子类遮蔽的基类上的成员。
  • 但我会建议使用 declval,因为即使 decltype(B::a) 工作 decltype(B) 也不能,你可能会混淆你的代码的读者。为了清楚起见,请坚持使用 decltype(std::declval&lt;B&gt;())decltype(std::declval&lt;B&gt;().a)
  • Re:“你会得到一个空指针异常并崩溃”——或者你可能没有那么幸运,代码会运行“很好”。当然,直到您向最重要的客户提供了一个演示,而那是它会崩溃的时候。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-16
  • 2010-11-19
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多