16

A deleted answer on this question about a deleted move constructor quotes cppreference.com as saying that the is_move_constructible trait should succeed as long as a move constructor is "accessible", even if it's not "usable".

The standard in fact requires that move-construction of the argument type be well-formed, so the answer was not quite right.

Now, the standard repeatedly uses the term "accessible" in relation to constructors referring to actual constructibility. For example:

[C++11 8.5/6]: To default-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is an array type, each element is default-initialized;
  • otherwise, no initialization is performed.

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

However, I can't find anywhere in the standard that states categorically whether a deleted, explicitly-defined constructor is "accessible" or not.

A different [non-normative] quote seems to suggest that deleted-ness and accessibility are orthogonal:

[C++11: 12.2/1]: [..] [ Note: even if there is no call to the destructor or copy/move constructor, all the semantic restrictions, such as accessibility (Clause 11) and whether the function is deleted (8.4.3), shall be satisfied. [..]

  • Have I missed a passage?
  • If not, should the cppreference.com page be corrected? Can you suggest a better wording?
  • Should the standard be clearer about this either way?
Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 2
    I believe that accessibility refers to *names*, not definitions. – Kerrek SB Dec 28 '13 at 15:52
  • Calling a deleted function is ill-formed, so there isn't any more need in the text you quote. The quoted part just seems to be there for clarity reasons – Johannes Schaub - litb Dec 28 '13 at 15:52
  • 2
    @KerrekSB in the standard, *accessibility* **magically** refers also to constructors. But the Standard never says how that works. – Johannes Schaub - litb Dec 28 '13 at 15:53
  • 3
    Check out 12.1/5: "a function that is deleted **or** inaccessible". It seems indeed that the notions are independent. And again in 12.4/5: "has a deleted destructor **or** a destructor that is inaccessible" – Kerrek SB Dec 28 '13 at 15:54
  • @JohannesSchaub-litb: I think accessibility also refers to arbitrary *class members and bases*. – Kerrek SB Dec 28 '13 at 15:54

2 Answers2

12

I don't want to address what the cppreference website says, but as far as the standard is concerned, constructibility is not defined in terms of "accessible constructors". Rather, the primary definition is that of is_constructible, which is (C++11, 20.9.4.3/6):

is_constructible<T, Args...>

shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:

T t(create<Args>()...);

Access checking is performed as if in a context unrelated to T and any of the Args. Only the validity of the immediate context of the variable initialization is considered.

So the well-formedness of the hypothetical expression on the last line of code is the defining charac­ter­istic for the constructibility traits. And that works hand-in-hand with the clause that says that using a de­leted function leads to an ill-formed program.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
9

From the second quote in the question, I'd say that accessibility is not affected by deletedness, and that the first quote actually doesn't at all cover the case that such a constructor may be deleted.

This scenario is instead covered by a sort of "catch-all" requirement in the definition of delete:

[C++11: 8.4.3/2]: A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. —end note ]

So, cppreference.com could probably do with a note that there is a further criterion that applies to the is_move_constructible trait, than simply whether the move constructor is accessible. And there's a further problem here, which is that MoveConstructible can be satisfied by CopyConstructible too, so even the move constructor on its own is not strictly necessary.

This all raises another interesting point, though, that any possible implementation of is_move_constructible must surely "refer" to the deleted move constructor, which renders the program ill-formed as stated in the quote above. Still, I suppose with SFINAE tricks an implementation can avoid actually becoming ill-formed.


"A type with no move ctor at all but with a copy-ctor is move-constructible (constructible from an rvalue)." — DyP

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • *"than simply whether the move constructor is accessible"* A type with no move ctor at all but with a copy-ctor is move-constructible (constructible from an rvalue). – dyp Dec 28 '13 at 15:48
  • @DyP: I use the definition of "refer" that I quoted in the answer! Which indeed includes "if a function is overloaded, it is referenced only if the function is selected by overload resolution". – Lightness Races in Orbit Dec 28 '13 at 15:55
  • Huh? (OK I should have read the last sentence of that note, which says the same ;) but why does it then *need* to refer to the deleted move ctor? – dyp Dec 28 '13 at 15:57
  • @DyP if you have a container like `std::vector`, you'll get an implicit use of the move ctor for all the elements if and only if the move ctor is `noexcept`, otherwise the elements will be copied 1 by 1. I can't see how you can assume this kind of stuff. example: http://stackoverflow.com/a/8864895/2485710 – user2485710 Dec 28 '13 at 16:00
  • [Here's a quick-and-dirty implementation of `is_move_constructible`](http://coliru.stacked-crooked.com/a/65dd24ed28688465). g++4.8.1 raises errors if the chosen ctor is inaccessible (as in `private`), but not clang++3.4 -- I'm not sure which one is right :/ – dyp Dec 28 '13 at 16:07
  • @user2485710 What does `std::vector` have to do with move-constructibility in general? – dyp Dec 28 '13 at 16:32
  • @DyP because a vector is simply a set of values with the same type, thus you can't say that a type is move-constructable without verifying the semantic. – user2485710 Dec 28 '13 at 16:49
  • @user2485710 I use the term "move-constructible" in the sense of the Standard's `MoveConstructible` and `std::is_move_constructible`. Those have nothing to do with semantics, they don't even tell you whether or not the type has a move-ctor. – dyp Dec 28 '13 at 17:22
  • 3
    I fixed up [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) and some related things on cppreference to match the std a bit more. Better? – Cubbi Dec 28 '13 at 20:13
  • @Cubbi: _Much_ better! My eternal gratitude. – Lightness Races in Orbit Dec 29 '13 at 00:51