An abstract class shall not be used as a parameter type, as a function return type, or as the type of an explicit conversion. Pointers and references to an abstract class can be declared.This is troublesome, because it requires checking a property only known once a type is complete at a position (declaring a function) where the rest of the language permits incomplete types to appear.
In practice, this introduces spooky "backward-in-time" errors:
struct S; S f(); // #1, ok // lots of code struct S { virtual void f() = 0; }; // makes #1 retroactively ill-formed
This paper resolves the following core issues:
Beyond the ability to declare functions with incomplete return and parameter types, the standard also allows for the return type to be inspected using decltype(f()) even if it is incomplete. This ability might be used in template metaprogramming, and it should not break if one of the involved types happens to be abstract.
There are two approaches to solving this issue:
Therefore, the proposed wording chooses the second option.struct S; S f(); // ok, abstract-ness not checked here struct S { virtual void f() = 0; }; S f(); // error: S is abstract
It is recommended to treat this as a Defect Report against earlier versions of C++.
Change in 8.2.1 [basic.lval] paragraph 9:A program is ill-formed ifIn the definition ofanyan objectgives the, the type of that object shall not be an incomplete type (6.7 [basic.types]), an abstract class type (13.4 [class.abstract]), or a (possibly multi-dimensional) array thereof.
Unless otherwise indicated (Change in 8.5.1.2 [expr.call] paragraph 7:8.5.1.2 [expr.call]10.1.7.2 [dcl.type.simple]), a prvalue shall always have complete type or the void type; if it has a class type or (possibly multi-dimensional) array of class type, that class shall not be an abstract class (13.4 [class.abstract]).
... When a function is called,Change in 10.1.7.2 [dcl.type.simple] paragraph 5:the parameters that have object type shall have completely-defined object typethe type of any parameter shall not be a class type that is either incomplete or abstract. [ Note:thisThis still allows a parameter to be a pointer or reference toan incomplete class typesuch a type. However, it prevents a passed-by-value parameter to have an incomplete or abstract class type. -- end note ] ...
If the operand of a decltype-specifier is a prvalue, the temporary materialization conversion is not applied (7.4) and no result object is provided for the prvalue. The type of the prvalue may be incomplete or an abstract class type.Change in 11.3.4 [dcl.array] paragraph 1:
... T is called the array element type; this type shall not be a reference type, cvChange in 11.3.5 [dcl.fct] paragraph 12:void
, or a function typeor an abstract class type. ...
Types shall not be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete or abstract (possibly cv-qualified) class type in the context of the function definition unless the function is deleted (11.4.3).Editorial note: I suggest to move the statement about function definitions to 11.4 [dcl.fct.def].)
Change in 12.2 [class.mem] paragraph 14:
Change in 13.4 [class.abstract] paragraph 2:Non-staticThe type of a non-static datamembersmember shall nothavebe an incompletetypestype (6.7 [basic.types]), an abstract class type (13.4 [class.abstract]), or a (possibly multi-dimensional) array thereof. [ Note: In particular, a class Cshall notcannot contain a non-static member of class C, but it can contain a pointer or reference to an object of class C.-- end note ]
Change in 13.4 [class.abstract] paragraph 3:An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function. [ Note: Such a function might be inherited: see below. -- end note ]A virtual function is specified as a pure virtual function by using a pure-specifier (12.2) in the function declaration in the class definition. [ Note: Such a function might be inherited: see below. -- end note ] A class is an abstract class if it has at least one pure virtual function. [ Note: An abstract class can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it (6.1 [basic.def], 12.2 [class.mem]). -- end note ] A pure virtual function need be defined only if called with, or as if with (15.4), the qualified-id syntax (8.4).
Remove 17.9.2 [temp.deduct] paragraph 11 bullet 11:An abstract class shall not be used as a parameter type, as a function return type, or as the type of an explicit conversion. Pointers and references to an abstract class can be declared. [ Example:shape x; // error: object of abstract class shape* p; // OK shape f(); // error void g(shape); // error shape& h(shape&); // OK-- end example ][ Note: An abstract class type cannot be used as a parameter or return type of a function being defined (11.3.5 [dcl.fct]) or called (8.5.1.2 [expr.call]), except as specified in 10.1.7.2 [dcl.type.simple]. Further, an abstract class type cannot be used as the type of an explicit type conversion (8.5.1.9 [expr.static.cast], 8.5.1.10 [expr.reinterpret.cast], 8.5.1.11 [expr.const.cast]), because the resulting prvalue would be of abstract class type (8.2.1 [basic.lval]). However, pointers and references to abstract class types can appear in such contexts. -- end note ]
Change in 18.1 [except.throw] paragraph 3:
- ...
Attempting to create a function type in which a parameter type or the return type is an abstract class type (13.4 [class.abstract]).
If the type of the exception object would be an incomplete type, an abstract class type, or a pointer to an incomplete type other than cv void the program is ill-formed.