未物化的临时对象是否需要可访问析构函数?

Does an unmaterialized temporary needs the destructor to be accessible?

GCC 7.2 和 Clang 5.0 在这种情况下不一致:

struct A;

A foo();

struct A
  {
  static void bar()
     {
     foo();
     }
  private:
  ~A()=default;
  };

A foo()
  {
  return {};
  //GCC error: A::~A() is private in this context.
  };

此行为是 "c++17 guaranteed (copy elision and is not related RVO or NRVO)."

的一部分

GCC 不编译此代码,但 Clang 编译。哪一个是错误的?

也许这一段说机器人 Clang 和 GCC 符合标准 [class.temporary]:

When an object of class type X is passed to or returned from a function, if each copy constructor, move constructor, and destructor of X is either trivial or deleted, and X has at least one non-deleted copy or move constructor, implementations are permitted to create a temporary object to hold the function parameter or result object. The temporary object is constructed from the function argument or return value, respectively, and the function’s parameter or return object is initialized as if by using the non-deleted trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object). [ Note: This latitude is granted to allow objects of class type to be passed to or returned from functions in registers. — end note ]

我认为这是一个 clang 错误。

来自[class.temporary]

Temporary objects are created [...] when needed by the implementation to pass or return an object of trivially-copyable type (see below), and [...]

Even when the creation of the temporary object is unevaluated ([expr.prop]), all the semantic restrictions shall be respected as if the temporary object had been created and later destroyed. [ Note: This includes accessibility and whether it is deleted, for the constructor selected and for the destructor. However, in the special case of the operand of a decltype-specifier ([expr.call]), no temporary is introduced, so the foregoing does not apply to such a prvalue. — end note ]

foo 的 return 的复制初始化是一个创建临时对象的上下文,因此仍然必须遵循语义限制 - 其中包括析构函数的可访问性(作为注意有助于明确)。 ~A() 必须在此上下文中可访问,但不是,因此该程序应该是格式错误的。 gcc拒绝是正确的。

我认为这是 C++17 中的 gcc 错误。 根据copy elision:

since C++17

Under the following circumstances, the compilers are required to omit the copy- and move- construction of class objects even if the copy/move constructor and the destructor have observable side-effects. They need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:

In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.

In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue.

你的函数 foo return 是一个 A 类型的纯右值对象,return foo的类型是A,不管A是否可以访问copy/move 构造函数和析构函数,在C++17中将省略复制。