【问题标题】:__has_trivial_copy behaves differently in clang and gcc. Who's right?__has_trivial_copy 在 clang 和 gcc 中的行为不同。谁是对的?
【发布时间】:2012-10-05 22:33:26
【问题描述】:

std::is_trivially_copyable 在这两个编译器中仍然不受支持(至少就 gcc 4.6 而言)。但两者都提供了做得很好的__has_trivial_copy 指令。 除非涉及到已删除的复制构造函数。

struct A { A(A const&) =delete; };

__has_trivial_copy(A) 在 clang 中返回 1,在 gcc 中返回 0。

我正在研究标准,找不到一个子句说明在删除复制构造函数时该类是否仍被视为可简单复制。

谁是对的?

我倾向于相信 gcc 是正确的,因为 struct A 根本不可复制,更不用说可复制了。此外,还有一个广泛的共识,即删除的复制构造函数可以被视为私有声明但未定义的构造函数,在这种情况下 gcc 仍然是正确的。

另一方面,第 9/6 节中的标准描述了不具有任何非平凡操作的平凡可复制性。我想如果您按照书面标准阅读,clang 可能是对的。

【问题讨论】:

  • __has_trivial_copy(type)的规格是什么?? A 当然是可以简单复制的(memcpy 是它的一个实例没有问题)。肯定有一些 std::is_foobar 类型特征与核心语言 foobary 规范“矛盾”,但 C++ 标准中没有定义 __has_trivial_copy
  • 来自 gcc 文档: __has_trivial_copy (type) 如果 __is_pod (type) 为 true 或 type 是引用类型,则 trait 为 true,否则如果 type 是 cv 类或带有普通副本的联合类型构造函数 ([class.copy]) 则特征为真,否则为假。要求:类型应为完整类型、(可能是 cv 限定的)void 或未知边界数组。
  • 永远不要直接使用编译器钩子,你只是在麻烦。只需使用std::is_trivially_copyable
  • 恐怕当这两个编译器都引入std::is_trivially_copyable时,他们会简单地使用当前的机制,这是不兼容的。我明白 A 是可记忆的。
  • 从 gcc 文档的外观来看,__has_trivial_copy 听起来与std::is_trivially_copy_constructible 的关系比std::is_trivially_copyable 更密切。但别担心,g++ 库的家伙比只使用旧扩展并假设它是正确的更聪明。

标签: c++ c++11


【解决方案1】:

libc++,clang 的本机库,支持std::is_trivially_copyable<T>,并且实际上,在您的示例中假装该类型是可以简单复制的,尽管它显然不是简单可复制的。我认为,12.8 [class.copy] 第 12 段将删除的构造函数定义为非平凡的:

如果不是用户提供的,则 X 类的复制/移动构造函数是微不足道的......

删除的声明显然是用户提供的。当我在这里说“清楚”时,我的意思是我不能立即按照将函数声明为已删除的标准作为用户提供的函数来支持它......

进一步调查显示 8.4.2 [dcl.fct.def.default] 第 4 段(感谢 Jesse Good 提供参考)使已删除的函数不是用户提供的:

...一个特殊的成员函数是用户提供的,如果它是用户声明的并且在其第一次声明时没有明确地默认或删除。 ...

因此,如果没有其他理由使非平凡可复制(但这些都不适用于问题中的类型A),则具有已删除复制构造函数的类确实是可平凡复制的。这有点奇怪:类型type 无法使用其复制构造函数复制,但 可以 使用 std::memcpy() 复制!我不确定这是否真的是故意的。

【讨论】:

  • 来自 [8.4.2 显式默认函数]:A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.。所以,它不是用户提供的。
  • 但是,您提到的引用在我的副本中说 is user-provided or deleted,并且由于它已被删除,因此无法轻松复制。
  • @JesseGood:实际上,我正在看的文档并没有在此部分中提及“已删除”!也许我应该真正得到标准,这也可能是混乱的确切根源!
  • 实际标准这里也没有提到deleted
  • @JesseGood:你在看哪个文件?该标准绝对没有在 12.8 第 12 段中声明“或删除”!
【解决方案2】:

既不正确也不不正确,因为两者都在使用扩展。

警告:此答案基于 C++11 草案 N3242 中的文字,但最终标准中没有。所以不是特别好。留待比较和讨论。

您似乎想问什么:std::is_trivially_copyable<A>::value(还有std::is_trivially_copy_constructible<A>::value)必须是false

12.8 第 13 段:

如果类X 的复制/移动构造函数既不是用户提供也不是被删除,并且如果......

为了完整,

9 第 6 段:

可简单复制的类是这样的类:

  • 没有重要的复制构造函数 (12.8),
  • 没有重要的移动构造函数 (12.8),
  • 没有重要的复制赋值运算符(13.5.3、12.8),
  • 没有重要的移动赋值运算符(13.5.3、12.8),并且
  • 有一个简单的析构函数 (12.4)。

3.9 第 9 段:

标量类型、可平凡复制的类类型(第 9 条)、此类类型的数组以及这些类型的 cv 限定版本(3.9.3)统称为可平凡复制的类型

20.9.4.3 表 49:

模板:template <class T> struct is_trivially_copyable;

条件:T 是可简单复制的类型 (3.9)

【讨论】:

  • 您使用的是什么版本的文档?我正在查看最终草案,在 12.8/12 下(不是 12.8/26 也不是 12.8/2 下这是编辑前的原始版本)它说:类 X 的复制/移动构造函数是微不足道的,如果它不是用户提供的,如果...。什么都没有删除。
  • 哎呀,N3242 中的引文实际上应该是第 13 段。(26 用于作业。不知道 2 是从哪里来的。今晚我似乎遇到了数字问题。)
  • 嗯,我在看 3290。所以我猜我的文件胜过你的文件 :) 看起来“也没有删除”被取出了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多