C++ had adopted the original 
1. Revision History
1.1. R1
- 
     Retargeted to C++26. 
- 
     Rebase onto [N4958], which includes [P2361R6] so remove a note for it. 
- 
     Since [P2741R3] had been adopted in Varna (2023-06), add a section for it. 
- 
     Add previous poll result for [N4186]. 
- 
     In Kona (2023-11), EWGI sees D2573R1 and forwarded it to EWG with the following poll: 
Poll: Given the committee’s limited time, EWGI believes P2573R1 is sufficiently developed and motivated to forward to EWG (and mark for LEWG).
| SF | F | N | A | SA | 
| 4 | 4 | 3 | 0 | 0 | 
Outcome: Consensus 🎉
- 
     Add several notes on topics discussed in EWGI meeting. 
1.2. R0
- 
     Initial revision. 
2. Motivation
Introduced in C++11, 
The primary power of this approach is twofold. First, use of default language facilities can be made an error by deleting the definition of functions that they require. Second, problematic conversions can be made an error by deleting the definition for the offending conversion (or overloaded function).
Looking back at present, ten years after the introduction of deleted functions, we can confidently conclude that 
There are several reasons we preferred deleted functions over the traditional 
In other words, usage of 
The library author is saying, "I know what you’re trying to do, and what you’re trying to do is wrong." (Source)
and after this proposal, my hope is that such usage will mean
The library author is saying, "I know what you’re trying to do, and what you’re trying to do is wrong. However, I can tell you why I think it is wrong, and I can point you to the right thing to do."
The proposed syntax for this feature is (arguably) the "obvious" choice: allow an optional string-literal to be passed as an argument clause to 
void newapi (); void oldapi () = delete ( "This old API is outdated and already been removed. Please use newapi() instead." ); template < typename T > struct A { /* ... */ }; template < typename T > A < T > factory ( const T & ) { /* process lvalue */ } template < typename T > A < T > factory ( const T && ) = delete ( "Using rvalue to construct A may result in dangling reference" ); struct MoveOnly { // ... (with move members defaulted or defined) MoveOnly ( const MoveOnly & ) = delete ( "Copy-construction is expensive; please use move construction instead." ); MoveOnly & operator = ( const MoveOnly & ) = delete ( "Copy-assignment is expensive; please use move assignment instead." ); }; 
There is a tony table of how a non-copyable class evolves from C++98 to this proposal, thus introducing the benefits of the proposal and the user-friendliness it brings. All the examples (except the hypothetical one) are generated by x86-64 clang version 14.0.0 on Compiler Explorer. The usage client is
int main () { NonCopyable nc ; NonCopyable nc2 = nc ; ( void ) nc2 ; } 
| Standard | Code | Diagnostics / Comment | 
| C++98 | 
 | 
 | 
| Average user probably don’t know what " constructor" means. Also,/member usage still result in link-time error only. | ||
| C++11 (present) | 
 | 
 | 
| Great improvement: we can teach "deleted" means "usage is wrong" constantly, and everything is compile-time error. However, still for average user a bit hard to understand and don’t point out what to do instead. | ||
| This proposal | 
 | 
 | 
| With minimal change, we get a huge boost in user/beginner friendliness, with ability to explain why and what to do instead. | 
3. Usage Example
3.1. Standard Library
This part contains some concrete examples of how current deleted functions in the standard library can benefit from the new message parameter. All examples are based on [N4958].
Note: As will be discussed below, the standard does not mandate any diagnostic text for deleted functions; a vendor has the freedom (and is encouraged by this proposal) to implement these messages as non-breaking QoI features.
// [unique.ptr.single.general] namespace std { template < class T , class D = default_delete < T >> class unique_ptr { public : // ... // disable copy from lvalue unique_ptr ( const unique_ptr & ) = delete ( "unique_ptr<T> resembles unique ownership, so copy is not supported. Use move operations instead." ); unique_ptr & operator = ( const unique_ptr & ) = delete ( "unique_ptr<T> resembles unique ownership, so copy is not supported. Use move operations instead." ); } } // [memory.syn] namespace std { // ... template < class T > constexpr T * addressof ( T & r ) noexcept ; template < class T > const T * addressof ( const T && ) = delete ( "Cannot take address of rvalue." ); // ... template < class T , class ... Args > // T is not array constexpr unique_ptr < T > make_unique ( Args && ... args ); template < class T > // T is U[] constexpr unique_ptr < T > make_unique ( size_t n ); template < class T , class ... Args > // T is U[N] unspecified make_unique ( Args && ...) = delete ( "make_unique<U[N]>(...) is not supported; perhaps you mean make_unique<U[]>(N) instead?" ); } // [basic.string.general] namespace std { template < class charT , class traits = char_traits < charT > , class Allocator = allocator < charT >> class basic_string { public : // ... basic_string ( nullptr_t ) = delete ( "Construct a string from a null pointer is undefined behavior." ); } 
3.2. Other
A hypothetical usage of new 
4. Design
4.1. Previous Work
There have been three previous example of user-customisable error messages presented currently in the C++ standard:- 
     C++11 static_assert ( expr , "message" ) 
- 
     C++14 [[ deprecated ( "with reason" )]] 
- 
     C++20 [[ nodiscard ( "with reason" )]] 
This proposal naturally fits in the same category of providing reasons/friendly messages alongside the original diagnostics and can use a lot of the existing wordings.
A previous proposal, [N4186], proposed the exactly same thing, and is received favorably by EWG in Urbana (2014-11) (see [EWG152]):
Poll: Is this a problem worth solving?
SF F N A SA 13 5 1 3 2 
However, there is no further progress on that proposal, and thus this proposal aims to continue the work in this direction.
4.2. Syntax and Semantics
The syntax I prefer is=  delete ( "with reason" ); delete The semantics will be entirely identical to regular 
4.3. Alternative Design and Issues
This section lists the alternative design choices and possible arguments against this proposal that have been considered.4.3.1. Alternative Syntax
A previous proposal [P1267R0] proposed a[[ reason_not_used ( "reason" )]] =  delete [[ reason_xxx ]] [[ reason_deleted ( "reason" )]] void fun () = delete ( "my reason" ); 
which in future-[P1267R0] world will be expressed as
[[ reason_deleted ( "my reason" )]] void fun () = delete ; 
Personally, comparing these two syntaxes, I prefer the proposed 
Of course, given that the function-body part of the grammar is relatively free, other (arcane?) syntax like 
4.3.2. Overriding Semantics
One of the new issues brought up by this new syntax is the overriding problem:struct A { virtual void fun () = delete ( "reason" ); }; struct B : public A { void fun () override = delete ( "different reason" ); }; 
Should overriding with a different (or no) message parameter be supported? (Notice that you cannot override deleted functions with non-deleted ones or vice versa, so this is the only form.)
I believe that this should be supported for the following reason:
- 
     Changing = delete 
- 
     Existing attributes allow this (and even went further, allow an overriding function to change from having attribute to not having). 
4.3.3. Locales and Unevaluated Strings
I heard that there had been already some discussion in the committee for this proposal, probably in the discussion phase of [P1267R0]; the hesitancy is basically that the string-literals being accepted in the structure is unrestricted, thus may raise some doubt on how to handle things like=  delete ( L"Wide reason" ); However, this is not a problem unique to this proposal. This problem also applies to the other three existing examples, and there is [P2361R6] to solve this problem in general. Therefore I do not see any reason locales of unevaluated strings should be an obstacle.
As for the problem of displaying text that cannot be represented in the execution character set, this paper follows the existing [P2246R1] changes to 
4.3.4. Claim of Syntax Space
During EWGI review of this paper, some people expressed concern on the possibility of this proposal "claiming the syntax space" of possible further enhancement to=  delete =  delete explicit =  delete void foo () = delete ( sizeof ( int ) != 4 ); 
I think this argument is ungrounded for two reasons:
- 
     First of all, this proposal do not actually claim the full syntax space for the argument after = delete 
- 
     Secondly, I feel that = delete ( < conditional - expression > ) requires requires = delete 
4.4. Proposal Scope
This proposal is a pure language extension proposal with no library changes involved and is a pure addition, so no breaking changes are involved. It is intended practice that exchanging=  delete ; =  delete ( "message" ); There has been sustained strong push back to the idea of mandating diagnostic texts in the standard library specifications, and in my opinion, such complaints are justified. This paper does not change this by only proposing to make such "deleted with reason" ability available and nothing more.
This paper encourages vendors to apply any text they see fit for the purpose as a QoI, non-breaking feature.
4.5. Future Extensions
There have been suggestions on supporting arbitrary constant-expressions instatic_assert make_unique < int [ 5 ] > (...) is not supported ; perhaps you mean make_unique < int [] > ( 5 ) instead ? 
for the invocation 
During Varna (2023-06), [P2741R3] is adopted into the C++26 standard, giving 
Some people suggested considering the same message parameter for other keywords in the language, such as 
4.6. Target Vehicle
This proposal targets C++26.4.7. Feature Test Macro
The previous works all bump the relevant attributes or feature testing macros to a new value to resemble the change. However, C++11 default and deleted functions don’t have a feature test macro, so I propose to include a new language feature testing macro__cpp_deleted_function_with_reason 5. Implementation Experience
An experimental implementation of the proposed feature is located in my Clang fork at [clang-implementation], which is capable of handling
void foo () = delete ( "Reason" ); void fun () { foo ();} 
and output the following error message: (close to what I want; of course, there are other formats such as put reason on separate lines)
propose . cpp : 2 : 13 : error : call to deleted function 'foo ': "Reason" void fun () { foo ();} ^~~ propose . cpp : 1 : 6 : note : candidate function has been explicitly deleted void foo () = delete ( "Reason" ); ^ 1 error generated . 
The implementation is very incomplete (no support for constructors, no feature-test macro, only a few testing, etc.), so it is only aimed at proving that the vendors can support the proposed feature relatively easily.
6. Wording
The wording below is based on [N4958].
Wording notes for CWG and editor:
- 
     This wording factors existing = delete ; 
- 
     The current wording is basically a combination of static_assert [[ nodiscard ]] 
6.1. 9.5 Function definitions [dcl.fct.def]
6.1.1. 9.5.1 In general [dcl.fct.def.general]
Function definitions have the form
function-definition:
    attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
    attribute-specifier-seqopt decl-specifier-seqopt declarator requires-clause function-body
function-body:
    ctor-initializeropt compound-statement
    function-try-block
    = default ;
    = delete ;deleted-function-body
deleted-function-body:
    = delete ;
    = delete ( unevaluated-string ) ;
   6.1.2. 9.5.3 Deleted definitions [dcl.fct.def.delete]
Clause 1:A deleted definition of a function is a function definition whose function-body is of the form
deleted-function-body or an explicitly-defaulted definition of the function where the function is defined as deleted. A deleted function is a function with a deleted definition or a function that is implicitly defined as deleted.= delete ; 
Clause 2:
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed
., and the resulting diagnostic message ([intro.compliance]) should include the text of the unevaluated-string, if one is supplied.
[Note 1: 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. For an overload set, only the function selected by overload resolution is referenced. The implicit odr-use ([basic.def.odr]) of a virtual function does not, by itself, constitute a reference. The unevaluated-string, if present, can be used to explain the rationale for why the function is deleted and/or to suggest a replacing entity. — end note]
6.2. 15.11 Predefined macro names [cpp.predefined]
In [tab:cpp.predefined.ft], insert a new row in a place that respects the current alphabetical order of the table, and substituting20 XXYYL | Macro name | Value | 
|  |  |