Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__has_trivial_copy behaves differently in clang and gcc. Who's right?

Tags:

c++

c++11

std::is_trivially_copyable is still not supported in either of those two compilers (at least as far as gcc 4.6). But both provide __has_trivial_copy directives that do pretty good job. Except when it comes to deleted copy constructors.

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

__has_trivial_copy(A) returns 1 in clang and 0 in gcc.

I was digging in the standard and could not find a clause that says whether the class is still considered trivially copyable when the copy constructor is deleted.

Who's right?

My inclination is to believe that gcc is right, because struct A is not copyable at all, let alone trivially copyable. Also, there's a wide-spread consensus, that a deleted copy constructor can be seen as a privately declared, but not defined constructor, in which case gcc would still be right.

On the other hand, the standard in section 9/6 describes trivial-copyability in terms of not having any non-trivial operations. I guess if you read the standard as written, clang may be right.

like image 433
Andy Venikov Avatar asked Oct 05 '12 22:10

Andy Venikov


2 Answers

libc++, clang's native library, supports std::is_trivially_copyable<T> and, indeed, pretends on your example that the type is trivially copyable although it is clearly not trivially copyable. I think, 12.8 [class.copy] paragraph 12 defines the deleted constructor as non-trivial:

A copy/move constructor for class X is trivial if it is not user-provided ...

The deleted declaration is clearly user-provided. When I say "clearly" here I mean that I can't immediately back it up by the standard that declaring a function as deleted counts as user-provided...

Further investigation reveals that 8.4.2 [dcl.fct.def.default] paragraph 4 (thanks to Jesse Good for providing the reference) makes a deleted function non-user-provided:

... A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. ...

Thus, a class with a deleted copy constructor is indeed trivially copyable if there is no other reason to make non-trivially copyable (but none of those applies to the type A in the question. That's a bit weird: type type cannot be copied using its copy constructor but it can be copied using std::memcpy()! I'm not sure if this is really intentional.

like image 187
Dietmar Kühl Avatar answered Nov 02 '22 22:11

Dietmar Kühl


Neither is correct or incorrect, since both are using extensions.

Warning: This answer was based on words which were in C++11 draft N3242, but are not in the final Standard. So it's not especially good. Leaving it up for comparison and discussion.

For what it seems you meant to ask: std::is_trivially_copyable<A>::value (and also std::is_trivially_copy_constructible<A>::value) must be false.

12.8 paragraph 13:

A copy/move constructor for class X is trivial if it is neither user-provided nor deleted and if....

And just to be complete,

9 paragraph 6:

A trivially copyable class is a class that:

  • has no non-trivial copy constructors (12.8),
  • has no non-trivial move constructors (12.8),
  • has no non-trivial copy assignment operators (13.5.3, 12.8),
  • has no non-trivial move assignment operators (13.5.3, 12.8), and
  • has a trivial destructor (12.4).

3.9 paragraph 9:

Scalar types, trivially copyable class types (Clause 9), arrays of such types, and cv-qualified versions of these types (3.9.3) are collectively called trivially copyable types.

20.9.4.3 Table 49:

Template: template <class T> struct is_trivially_copyable;

Condition: T is a trivially copyable type (3.9)

like image 32
aschepler Avatar answered Nov 02 '22 22:11

aschepler