2960. [fund.ts.v2] nonesuch is insufficiently useless

Section: 99 [fund.ts.v2::meta] Status: New Submitter: Tim Song Opened: 2017-05-08 Last modified: 2017-11-24

Priority: 2

View all issues with New status.

Discussion:

Addresses: fund.ts.v2

The definition of std::experimental::nonesuch (with a deleted default constructor, destructor, copy constructor, and copy assignment operator) means that it is an aggregate, which means that it can be initialized from {} in contexts where the availability of the destructor is not considered (e.g., overload resolution or a new-expression).

The deleted default constructor also has this effect standing alone, because it doesn't affect the formation of implicit conversion sequences (and hence overload resolution). The net result is ambiguities in situations like:

struct such {};
void f(const such&);
void f(const nonesuch&);
f({});

For a real-life example of such ambiguity, see GCC bug 79141, involving libstdc++'s internal __nonesuch type defined just like the one in the fundamentals TS.

I believe that nonesuch would be substantially more useful if the ICS from {} is gone. nonesuch should have no default constructor (rather than a deleted one), and it shouldn't be an aggregate.

[2017-11-20 Priority set to 2 after discussion on the reflector.]

Proposed resolution:

This wording is relative to N4617.

  1. Edit 23.15.2 [meta.type.synop] as indicated, moving the definition of nonesuch to [fund.ts.v2::meta.detect]:

    // [fund.ts.v2::meta.detect], Detection idiom
    […]
    
    struct nonesuch{
      nonesuch() = delete;
      ~nonesuch() = delete;
      nonesuch(nonesuch const&) = delete;
      void operator=(nonesuch const&) = delete;
    };
    […]
    

  2. Insert at the beginning of [fund.ts.v2::meta.detect] the following paragraphs:

    [Drafting note: The seemingly redundant statement about default and initializer-list constructors is intended to negate the usual leeway for implementations to declare additional member function signatures granted in 20.5.5.5 [member.functions]. — end drafting note]

    struct nonesuch {
      ~nonesuch() = delete;
      nonesuch(nonesuch const&) = delete;
      void operator=(nonesuch const&) = delete;
    };
    

    -?- nonesuch has no default constructor (C++14 §[class.ctor]) or initializer-list constructor (C++14 §[dcl.init.list]), and is not an aggregate (C++14 §[dcl.init.aggr]).