[HN Gopher] What =delete means
       ___________________________________________________________________
        
       What =delete means
        
       Author : todsacerdoti
       Score  : 92 points
       Date   : 2021-10-18 13:07 UTC (9 hours ago)
        
 (HTM) web link (quuxplusone.github.io)
 (TXT) w3m dump (quuxplusone.github.io)
        
       | cogman10 wrote:
       | So I read the article, and maybe I'm thick... but what does
       | `=delete` mean? I saw a bunch of examples about how it will
       | trigger errors with l/rvalues in some scenario, but I'm really no
       | clear on the meaning of it.
       | 
       | Would someone mind explaining the meaning? Is it some sort of
       | lifetime opt-in thing? Is it restricting how a method can be
       | called? What's going on here? What is `=delete` telling the
       | compiler?
        
         | syncsynchalt wrote:
         | To explain from another direction, and add to the replies
         | you're getting that explain it directly, C++ is a language that
         | does its best to not break existing codebases.
         | 
         | When they want to introduce a new concept (in this case, a way
         | to express that using an implicit function or overload is
         | forbidden) they use one of the already-reserved keywords
         | ("delete"). This sometimes leads to a clunky reading
         | experience, but is better than breaking anyone's code that
         | happens to use a variable or function named "forbidden" or
         | similar.
        
           | TFortunato wrote:
           | Yes, this part is super relevant to answer WHY it is written
           | the way it is.
           | 
           | C++ has a lot of nice ideas under the hood, but the syntax
           | and reading experience definitely isn't ideal because of the
           | desire for backwards compatibility (which includes the very
           | strong desire to not introduce new keywords / tokens if there
           | is any possible way to avoid it)
        
         | jcelerier wrote:
         | = delete; allows your users to get a nice compiler error
         | messages when they call a function you don't want them to call,
         | by mistake.
         | 
         | This can allow for instance to explicitely erase overloads and
         | "disable" functions or methods. For instance imagine that you
         | don't want a function to be called with a float, just with a
         | double, because having floats creeping in somewhere would be a
         | bug and you want to catch as many bugs as possible: then you
         | can just do the following.                   void foo(float) =
         | delete;         void foo(double) { }                  int
         | main()         {           // won't compile:
         | foo(1.23f);                // will compile:
         | foo(1.23);         }
         | 
         | without the following line:                   void foo(float) =
         | delete;
         | 
         | 1.23f would be implicitely converted to a double instead of
         | causing a compile error.
         | 
         | One case where I found it super useful is for instance to
         | disable constructors taking a pointer when you have ctors
         | taking a bool:                   struct foo {
         | template<typename T>           foo(T*) = delete;
         | foo(bool);         };              int main()         {
         | void* x = nullptr;           // won't compile: foo f(x);
         | // won't compile: foo g("blablaba");         }
         | 
         | this (rightly) causes a compile error on both the creation of f
         | and g, while if foo(T*) = delete; was not there then
         | conversions from ptr to bool would happen:
         | struct foo {           foo(bool);         };              int
         | main()         {           void* x = nullptr;           foo
         | f(x); // compiles :'(           foo g("blablaba"); // compiles
         | :'(         }
        
         | pjmlp wrote:
         | A very basic and quite high level explanation is as follows.
         | 
         | In several cases the C++ compiler will generate default
         | implementation for specific methods.
         | 
         | However there are cases where that isn't desirable, and until
         | =delete came to be, the workaround was to mark the method as
         | private without implementation.
         | 
         | So =delete deals away with such hack, although as mentioned
         | this is a superficial overview of its purpose.
        
           | cogman10 wrote:
           | Ok, that's the C++ I learned many moons back (C++98/03). And
           | it makes sense why that exists. Thanks.
        
         | TFortunato wrote:
         | You're definitely not thick! This is getting a bit into the
         | weeds of lower-level C++, but it is useful. So what delete is
         | doing is explicitly saying that a given method (with a
         | particular signature) is defined to not exist. It's usually
         | used in cases where the compiler would automatically create a
         | method for you, or use a method you wouldn't want to be used.
         | 
         | The example they give is the reference wrapper, which (as the
         | name might suggest), is used to wrap a reference to some thing.
         | To reiterate, with hopefully a bit more of what is going on.
         | 
         | If the creator of this method had just created a function:
         | 
         | template<class T> auto cref(const T&) ->
         | std::reference_wrapper<const T>;
         | 
         | Then by C++ overloading rules, you could call this function
         | with either an const ref LValue, or an RValue of type T. (In
         | their example, they used a number). Which for 95% of functions
         | is totally fine, and desired behavior! However, in this case,
         | it would be bad, because remember, we are trying to wrap a
         | reference to some value (e.g. basically a pointer under the
         | hood), so a pointer to some ephemeral value is likely not what
         | we want.
         | 
         | In order to solve this, the creator explicitly adds:
         | template<class T> auto cref(const T&&) = delete;
         | 
         | Now, if the user calls cref on an RValue like a number, they
         | will get a nice error message saying that the function has been
         | explicitly deleted. The reason this works is because "const
         | T&&" is the better match for the type of an RValue, compared to
         | "const T&", so this is the overload that the compiler will try
         | to use, rather than the original version above.
         | 
         | Some other reasons to use delete, is if you want to do stuff
         | like explicitly forbid the use of copy constructors, because
         | you have some object that you don't want copies made of for
         | whatever reason. By explicitly deleting the copy constructor,
         | you can be sure that no copies are accidentally made somewhere
         | in user code (which is especially useful when your code
         | interacts with other libraries you don't control)
         | 
         | I hope that made sense, but the TLDR is that there are a lot of
         | ways construct objects, delete objects, to copy / move data
         | around, etc. If you are doing low-level memory management /
         | optimization, you may want to explicitly tell the compiler not
         | to do the normal "helpful" stuff it does for you, such as
         | creating default constructors / overloads, and this is the
         | supported way of doing that in the standard.
        
           | cogman10 wrote:
           | Yup that makes a ton of sense, thanks.
        
       | butterisgood wrote:
       | Yes, it's a good idea to know the implicit rules for constructors
       | and assignment operators in C++.
       | 
       | No, it's not a bad idea to be as explicit as possible all the
       | time when writing code, because code is for humans first, and
       | computers second.
       | 
       | I always found =delete to be very nice documentation of what I
       | can expect of a struct, class etc in terms of valid uses.
       | 
       | And C++ is huge - assuming all the people on your team understand
       | all of it, and the corners and implicit behaviors is really not a
       | great idea. So you should remove any potential source of
       | confusion, or ambiguity in a source tree - as much as possible.
        
       | iulian_r wrote:
       | How do you handle failures in constructors without exceptions?
        
         | klyrs wrote:
         | The safest & fastest way I'm aware of to use a unique_ptr
         | factory. It involves adding an error flag to the class; the
         | factory checks the error flag and resets the unique_ptr if it's
         | true.
        
           | nyanpasu64 wrote:
           | C++ constructors cannot express fallibility. Rust factory
           | functions cannot placement-initialize (write into a pointer)
           | an object too big to fit on the stack (aside from the perma-
           | unstable `box` syntax, which I don't know if it even works or
           | not). A unique_ptr factory cannot stack-allocate an object.
           | 
           | I don't know if it's possible to create a safe interface to
           | fallible initialization, which is agnostic to whether the
           | object will be constructed via return onto the stack, or onto
           | heap memory. I'm interested to hear about proposals though
           | (I've discussed this in the Rust community discord, but that
           | isn't as public or concrete as a long-form article).
        
             | klyrs wrote:
             | > C++ constructors cannot express fallibility.
             | 
             | No, they can. They can throw exceptions. My suggestion
             | moves unsafe-construction onto the heap. Not ideal for a
             | whole host of reasons, including a need to null-check the
             | result -- but you can then move the object to the stack,
             | and drop the unique_ptr. But if you're tying one hand
             | behind your back, contortions will be necessary to
             | accomplish the mundane.
        
               | gpderetta wrote:
               | You can have a named factory function returning an
               | optional<T> (or your preferred fallible type).
        
               | klyrs wrote:
               | Right, right... I still haven't adopted the '17 features
               | yet.
        
         | ginko wrote:
         | In my company we do so by disallowing constructors to fail. If
         | an object needs to be initialized with the potential of failure
         | you need to call an init() function that returns an error code
         | after construction.
         | 
         | Yes, that makes RAII basically impossible.
        
           | kllrnohj wrote:
           | Why not a factory function that returns std::optional<T>
           | instead? Or better a variant of T or error code?
           | 
           | The construct-then-init pattern is so annoying to deal with.
        
           | ahartmetz wrote:
           | IMO the most important part of RAII is really the other side,
           | "destruction is resource divestment" - and that still works.
           | _That_ is the main purpose of lock guards, refcounting
           | wrappers, file objects and so on.
        
         | lkjlakj3334 wrote:
         | First of all, I'd avoid exceptions in constructors, regardless
         | of what programming language you use.
        
       | SavantIdiot wrote:
       | I'm so done with C++. When a fundamental keyword becomes a
       | semantic pitfall, you've created an esoteric niche for
       | enthusiasts, not a useful tool.
        
         | pansa2 wrote:
         | > _I 'm so done with C++._
         | 
         | But what to use instead? Especially in an industry like game
         | engine development, where C++ is basically all there is (and
         | almost all there's ever been)?
         | 
         | Are we forever going to be stuck with every company trying to
         | reduce complexity by defining their own custom subset of C++?
        
           | swalls wrote:
           | in the future, I think Jai looks pretty good, as a language
           | designed for game dev, considering they're basically battle
           | testing it by shipping a large 3d game in it... if the
           | compiler ever gets released. I think 7 years of streamed
           | development from Jonathan Blow?
        
           | dahart wrote:
           | > Are we forever going to be stuck with every company trying
           | to reduce complexity by defining their own custom subset of
           | C++?
           | 
           | Yes, probably? In 30 years of professional coding and a
           | decade of game engine development, I've never seen that not
           | be the case, all the companies I've been at and all the
           | companies I know about limit their C++ to a subset to try to
           | control complexity.
           | 
           | I'm curious if you're suggesting it would be better to
           | increase complexity by allowing all of C++? There are
           | definitely features I don't trust everyone with.
           | 
           | Complexity combined with engineer hubris is one of the big
           | problems with C++. While working in games, I witnessed many
           | people overengineering and being too clever by half, and
           | costing the team time and money. One of the most memorable
           | bugs I ever tracked down while working in games was a
           | release-build only crash where a programmer had tried to get
           | fancy with a copy constructor and bungled it unknowingly. We
           | had a team of 10 people working over a weekend trying to
           | catch it and I had to write a custom debugger to trap the
           | call stack. The cost of his trickery was easily in the
           | several tens of thousands of dollars at least. It only takes
           | that happening a few times before you realize C++ is a foot-
           | gun in many (most? all?) hands.
        
             | pansa2 wrote:
             | > _I'm curious if you're suggesting it would be better to
             | increase complexity by allowing all of C++?_
             | 
             | No, definitely not. I'm wondering if there might be a
             | language on the horizon that's suitable for game engine
             | development but which is substantially _less_ complex than
             | C++.
             | 
             | Or, if not, is there an effort to rally round a particular
             | subset of C++ instead of everyone defining their own? In
             | your experience, have the C++ subsets used in different
             | companies been very similar, or quite different?
        
               | TuringTest wrote:
               | _> No, definitely not. I'm wondering if there might be a
               | language on the horizon that's suitable for game engine
               | development but which is substantially less complex than
               | C++. Or, if not, is there an effort to rally round a
               | particular subset of C++ instead of everyone defining
               | their own?_
               | 
               | If it doesn't exist, it should be created and called _--
               | C_.
               | 
               | (C-- is already taken) https://en.wikipedia.org/wiki/C--
        
           | nynx wrote:
           | The main alternative is likely rust.
        
             | criddell wrote:
             | Are you saying that for game engine development, Rust is
             | the second most popular option?
        
           | SavantIdiot wrote:
           | I didn't say "You can't use it," I said "I" am done with it.
           | 
           | Have fun! Write some cool games!
        
             | pansa2 wrote:
             | Thanks for the encouragement, it's appreciated.
        
           | fullstop wrote:
           | Someone is going to say Rust, and I might agree with them at
           | some point in the future.
           | 
           | I periodically check https://www.areweguiyet.com/ to see the
           | state of things, but C++ is still king here.
           | 
           | I cut my teeth on C++ but was then employed to write code in
           | C. After almost two decades of doing this, C++ looks vastly
           | different to what I remember from 2001 and kind of ugly to
           | me. I'm sure, however, if I had stuck with C++ for the last
           | twenty years it would feel like home.
        
           | jerf wrote:
           | The places where you _must_ use C++ are a dwindling niche.
           | Large niches in their own right, certainly, but niches. Once
           | you leave those niches there is an explosion of
           | possibilities.
           | 
           | I'm coming up on year 25 of my career and I haven't touched
           | C++ since school, if one can indeed call what is covered in
           | school C++. Especially nowadays. And C and Java I've _barely_
           | touched. I certainly couldn 't put them on my resume with a
           | straight face.
           | 
           | I say this because you kind of sound like you're making some
           | sort of plaintive plea, as if C++ is somehow the only viable
           | option in the world and who could even dream of stepping
           | outside of it? And I'm telling you that while that may be
           | true in an ever-decreasing set of niches, it is not true in
           | general anymore and hasn't been for a long time.
        
           | professoretc wrote:
           | > Are we forever going to be stuck with every company trying
           | to reduce complexity by defining their own custom subset of
           | C++?
           | 
           | The problem with doing this is the same as with the idea that
           | one "90% of people only use 10% of Excel's features" so we
           | should be able to make a simpler Excel and capture 90% of the
           | market: all those people use a _different_ 10% subset. It 's
           | the same with C++; everyone wants a "simpler" language, but
           | no one agrees on what should be kept and what should be
           | thrown out. C++ is the language that results from putting
           | together everything that everyone needs (and then dealing
           | with the resulting conflicts and contradictions).
        
         | edflsafoiewq wrote:
         | What is the semantic pitfall here?
        
           | beached_whale wrote:
           | For almost everyone, none. delete doesn't remove the method
           | from the overload set, it leaves it there in order to give
           | the caller an error saying don't do that.
        
             | klyrs wrote:
             | It also prevents the compiler from emitting a default
             | implementation for the deleted method.
        
           | tialaramex wrote:
           | C++ has a keyword, "delete" which originally refers to an
           | operator that destroys objects, thus calling their destructor
           | and giving back resources (most obviously memory) allocated
           | for their lifetime.
           | 
           | But, adding keywords to C++ is expensive. You can't use these
           | as symbols, you can't name a class, a variable, a function or
           | anything "delete" because that's a keyword and so it's
           | reserved. A new keyword would clobber existing symbols, and
           | that's painful, so, C++ tries not to do it, instead
           | repurposing existing keywords.
           | 
           | So as well as the operator named "delete" now "delete" refers
           | to this feature where you can tell the compiler that this
           | particular overload mustn't be used, if it was looking for an
           | overload, it won't use this because you explicitly said not
           | to (even if it could have otherwise conjured a default) and
           | if somebody else called it by mistake now they get a compile
           | error saying not to.
           | 
           | I don't think they would naturally have written =delete if
           | not for being conscious that doing so is "free" (the word is
           | already reserved for something else) whereas some other word
           | would have caused compatibility problems.
        
             | cesarb wrote:
             | > A new keyword would clobber existing symbols, and that's
             | painful, so, C++ tries not to do it, instead repurposing
             | existing keywords.
             | 
             | It's even more painful than that. A new keyword could
             | conflict with a _macro_. So even contextual keywords
             | (something which is a keyword only in a place where
             | arbitrary symbols are not allowed, so there 's no conflict)
             | could be problematic.
        
             | edflsafoiewq wrote:
             | What, you think the syntax is funny? I guess, but that's
             | not a _semantic_ pitfall.
        
               | tialaramex wrote:
               | Previously delete referred to an operator
               | 
               | Today delete is both the operator and this entirely
               | unrelated feature, so that alters the meaning, a matter
               | of semantics.
               | 
               | Natural languages have plenty of such ambiguity, but C++
               | has a Committee (yes I know about French, no the Academie
               | Francaise doesn't actually get to decide how French
               | works, that's not how natural languages work) which could
               | have chosen to use a different word and did not.
        
               | [deleted]
        
               | edflsafoiewq wrote:
               | A semantic pitfall would be something where you think the
               | code means one thing (a patch of grass) but it really
               | means another (you fall into the spikes). =delete is
               | neither; it is not possible to confuse it for operator
               | delete, and I don't see even a hole to get your foot
               | stuck in, let alone any spikes.
        
               | squeaky-clean wrote:
               | > it is not possible to confuse it for operator delete,
               | 
               | I haven't written C++ in many years and my interpretation
               | of the code examples before reading the rest of the
               | article was that it was somehow binding it to the delete
               | operator as a function.
        
               | tialaramex wrote:
               | Fair. I wouldn't have chosen the phrase "semantic
               | pitfall", however after some thought I think it would
               | classify as a "hole to get your foot stuck in" because
               | it's unexpected in an artificial language to have this.
               | If you're a learner and you covered "delete" the operator
               | last week, then missed a day, and now there's = delete on
               | the slides, do you raise your hand to ask what's this
               | completely new syntax? No, right, it must somehow be the
               | delete operator you learned about, as otherwise it would
               | have a different name... wouldn't it?
               | 
               | But sure, C++ does have actual hidden spike traps, where
               | unwary programmers are going to hurt themselves badly by
               | mistake and this is not one of those.
        
               | jcranmer wrote:
               | Do you also complain that the operator named '*' is
               | overloaded? As a binary operator, it means to perform a
               | multiplication operator. As an unary operator, it means
               | to load the value located at that memory address, which
               | has nothing to do with anything close to multiplication.
               | That is a more gross alteration of semantics than the use
               | of a keyword in completely different slots (as an
               | expression versus as a declarator).
        
               | tialaramex wrote:
               | I'm not a fan of your example with the asterisk or of the
               | reference operator sharing a symbol with the binary AND
               | operator.
               | 
               | I don't like the use of + for concatenation much either,
               | even though it's overloaded to do that in some languages
               | I really like, and it's even _special cased_ despite the
               | lack of overloading in one language I think is fairly
               | good (Java) and some others I 've used but think are
               | garbage.
               | 
               | But I'm willing to cut some more slack for symbols
               | because they're short.
               | 
               | I think erase for example would have been a better choice
               | here (I haven't spent long thinking about this, the
               | committee had months), _but_ C++ had to worry about the
               | backwards compatibility penalty and that 's... sad.
        
               | agent327 wrote:
               | Actually it would have been a contextual keyword, meaning
               | it could be any word the committee wanted it to be, and
               | it is only recognized as such in this particular context
               | (i.e. at the end of a function declaration). They could
               | have chosen anything they wanted, but decided that
               | '=delete' was fine.
               | 
               | Other examples of contextual keywords are 'final' and
               | 'override', which may also occur on function
               | declarations.
        
               | hnfong wrote:
               | I guess they mean the "syntax-semantic mismatch pitfall"?
               | :)
        
               | jmull wrote:
               | A pointless semantic argument about the word semantic...
               | Thank you C++!
        
         | agent327 wrote:
         | It's just a piece of programming knowledge being explained.
         | It's very far from a 'semantic pitfall' or an 'esoteric niche'.
         | Don't be such a drama queen.
        
         | carpenecopinum wrote:
         | If a language feature being weird is enough to declare that
         | you're "done with it", you won't have too many languages to
         | work with in the end. Maybe some LISP, I guess?
         | 
         | You don't become a good craftsman by rejecting every tool that
         | isn't perfect. You become one by knowing your tools and their
         | flaws and strengths well.
        
           | SavantIdiot wrote:
           | > You become one by knowing your tools and their flaws and
           | strengths well.
           | 
           | Yes, that's why I said "I" am done with it, not "you should
           | be done with it." There's no need for me to use it ever.
           | Except when forced to with mbed, TFLiteMicro, and the
           | occasional port of an Arduino driver to C.
           | 
           | I've been at this since before C++ existed. I've watched it
           | come in to the world, and I've watched it mutate, Akira-like,
           | into an academic omphaloskepsis.
           | 
           | EDIT: Fun story: I learned C++ in ... 1990? ... by watching a
           | series of videos on VHS tape taught by none other than Bjarne
           | Stroustrup himself. I think it was a bonus that came with the
           | purchase of the first version of the Borland C++ compiler for
           | OS/2.
        
         | gpderetta wrote:
         | There is no semantic pitfall in = delete. = default on the
         | other hand...
        
         | codebolt wrote:
         | I'm with you. The only thing = delete means to me is that I'm
         | happy C++ isn't part of my dayjob.
        
         | jcelerier wrote:
         | > I'm so done with C++. When a fundamental keyword becomes a
         | semantic pitfall, you've created an esoteric niche for
         | enthusiasts, not a useful tool.
         | 
         | you think quux wouldn't be able to find semantic pitfalls in
         | literally every language you would use instead ?
        
           | tux3 wrote:
           | Some language designs have more semantic pitfalls than
           | others. All else equals, those would be preferable.
           | 
           | C++ is an old beast with many many footguns.
           | 
           | There's a more modern subset hiding inside, these days, but
           | let's not pretend every language has the same pitfalls that
           | C++ has.
        
             | jcelerier wrote:
             | sure, but there's also a deep culture in the C++
             | blogosphere to go and seek the deepest and darkest corners
             | and exhibit them as it's a very fun puzzle game. the same
             | people applied to Python, Java or LISP would yield endless
             | articles on pitfalls of those
        
               | SanFranManDan wrote:
               | If they are endless where are they?
        
               | pjmlp wrote:
               | Search for Java Puzzles books
        
               | tragomaskhalos wrote:
               | In the early 90's there were two print magazines: "The
               | C++ Report" and "The Smalltalk Report". The former, even
               | with the far simpler language it was then, was chock full
               | of programming arcana and 'what does this code do?' type
               | puzzles. The latter, by contrast, had effectively zero
               | such content. I loved both languages but this difference
               | was always very stark.
        
         | mikepurvis wrote:
         | I think for most of us mere mortals, the only normal use for
         | =delete is making a class non-copyable. And for that, my muscle
         | memory is already wired to inheriting from boost::noncopyable
         | anyway.
        
           | jpm48 wrote:
           | I put
           | 
           | private : myclass(const &myclass )=delete;
           | 
           | Just to be safe :-)
        
             | ziml77 wrote:
             | Funny thing there is that one could read that as saying
             | that the copy constructor's deletion is private and
             | therefore still accessible in the public interface. I
             | wouldn't put it past C++ to do something as crazy as that.
        
             | bialpio wrote:
             | IIRC this will make the compiler error less helpful than it
             | could be? I think you'd get an "attempt to use private
             | member" instead of "attempt to use deleted member". End
             | result is probably the same, but it feels like you're not
             | saying what you mean with the code.
             | 
             | Edit: NVM, looks like all major compilers will say that the
             | copy ctor is deleted. https://godbolt.org/z/jTd3714Tb
        
             | Psychlist wrote:
             | clang-tidy will ask that you put in the full set.
             | Foo() = delete;       Foo(const Foo& orig) = delete;
             | Foo(Foo&& orig) = delete;       Foo operator=(const Foo
             | &other) = delete;       Foo operator=(Foo &&other) =
             | delete;
             | 
             | (add const to taste)
        
         | simias wrote:
         | I must say that I'm always a bit in awe when I read modern C++
         | and I realize that I barely understand what's going on even
         | though ~10 years ago I considered that it was the language I
         | knew best. And even back then it was already a sprawling
         | monster of a language. Nowadays the idea of having to maintain
         | a large C++ codebase scares me. Too many footguns and arcane
         | knowledge required.
        
           | kllrnohj wrote:
           | Eh? '=delete' is a bad example of "footgun" or "arcane
           | knowledge". There are those in C++, sure, but this isn't one
           | of them.
           | 
           | You can happily never know the existence of '=delete' and
           | nothing about your code changes. And if you ever hit a
           | libraries usage of it, like the standard library, you get a
           | pretty clear error message at compile time instead of an
           | actual footgun in C++98 like memory corruption or runtime
           | crashes.
           | 
           | '=delete' is basically the entire reason why std::unique_ptr
           | is safe and std::auto_ptr is a footgun. It _reduces_ the ammo
           | aimed at yourself  & the amount of knowledge you need to know
           | (like the knowledge to never put auto_ptr in a vector)
        
             | simias wrote:
             | I was talking generally, not for this particular feature.
             | But it would still be sort of arcane knowledge for me since
             | when I last actively used C++ `=delete` either didn't exist
             | or was not in common use, so if I encountered it in some
             | codebase I'd probably guess what it does but still have no
             | idea about the implications.
             | 
             | Like, are there other =<something> construct? Is it
             | overridable or overloadable by the user? Can I use it to
             | "erase" any member of a class, for instance to hide a
             | parent member from an inherited class?
             | 
             | I suspect that the answer to all of these questions is
             | "no", but I can't know for sure without deep diving into
             | some C++ ref.
             | 
             | In the C++ I knew there was nothing resembling this syntax,
             | and `delete` was only the keyword you used to free memory.
        
               | kllrnohj wrote:
               | I would argue that's just "knowledge" not "arcane
               | knowledge". To me arcane knowledge is stuff like the
               | xvalues, prvalues, etc... Where it's both complex and
               | obscure. Where you can go down a headache-inducing rabbit
               | hole. This isn't really that, it's pretty simple, and
               | really only does that single thing. It doesn't have
               | complex interactions with anything else: https://en.cppre
               | ference.com/w/cpp/language/function#Deleted_...
               | 
               | As a sibling mentioned, it's not even a new syntax as '=
               | 0' has always been there.
        
               | cesarb wrote:
               | > Like, are there other =<something> construct?
               | 
               | Yes, there's "= 0" to mark a virtual method as not
               | implemented in this class (that is, it must be
               | implemented by a subclass), which is older than "=
               | delete". Conceptually, it sets the corresponding slot in
               | the virtual method table to null instead of a pointer to
               | the (non-existent) method, except that it actually
               | doesn't do that, it sets that slot to a pointer to a
               | "pure virtual method called" function from the standard
               | library, which AFAIK prints an error message and exits
               | the program (IIRC, this is because there are some
               | situations in which you can actually manage to call such
               | a pure virtual method, like calling it from a function
               | called within the constructor or destructor of the base
               | class.)
        
               | jdsully wrote:
               | A concrete object must implement all virtual methods
               | including those marked as pure virtual. All =0 means is
               | that someone else lower down the inheretence chain will
               | implement this and the caller using the class type can
               | rely on it existing.
               | 
               | If you try to instantiate an object without all methods
               | implemented you'll get a compiler error about the class
               | being "abstract". You should never have a case where
               | there's a null in the vtable.
               | 
               | If there is some specific edge case around ctors then
               | forgive me - this is C++ after all! But in practice you
               | don't have to worry about this which is true for most of
               | the C++ minutia.
        
               | cesarb wrote:
               | > If there is some specific edge case around ctors then
               | forgive me - this is C++ after all!
               | 
               | Yes, the specific edge case is around ctors and dtors.
               | During the ctor or the dtor, the vtable is the vtable of
               | the base class, not the derived class, so if you call a
               | virtual function within the ctor or dtor of the base
               | class (don't do that), the function which will be called
               | is the one from the (possibly abstract) base class. See
               | for instance this FAQ entry:
               | https://isocpp.org/wiki/faq/strange-inheritance#calling-
               | virt...
        
               | gpderetta wrote:
               | In addition to =0 mentioned elsethread, there is also
               | =default which will force the generation of a default
               | function that would be otherwise suporesed.
               | 
               | You can use =delete to delete any overload of a function,
               | be it class member or namespace scope.
               | 
               | Languages evolve; =delete and default were added to get
               | rid if a bunch of common hacks and the language is better
               | for that (at least for delete, default has a bunch of
               | pitfalls of its own unfortunately).
        
         | pjmlp wrote:
         | Until one delves into all the cool niche features being added
         | into Java, C#, F#, Python,...., even C.
         | 
         | Unless we are talking about v1.0 there always such cases when a
         | language is around long enough.
        
         | enriquto wrote:
         | > I'm so done with C++. When a fundamental keyword becomes a
         | semantic pitfall, you've created an esoteric niche for
         | enthusiasts
         | 
         | but it always was!
        
         | kccqzy wrote:
         | How is it a pitfall? The article clearly elucidates several
         | uses of the "=delete" construct. I don't see any pitfalls, just
         | some new uses of the feature. And I expect most people to be
         | the same: most people only ever use "=delete" on the copy
         | constructor and the copy assignment operator, now this article
         | tells them you can actually use it on other things too. There's
         | no pit to fall into, just new ways to use a feature.
        
       | cletus wrote:
       | It's well known that no one really programs in C++. They program
       | in whatever subset of C++ their organization allows, their brain
       | can handle or both.
       | 
       | Personally I found Google's C++ dialect to be sane, even
       | pleasant. No exceptions, no mutable reference parameters (side
       | note: this was a giant language fail that foo(f) could be a const
       | reference or a non-const reference and there's no way to know
       | without looking at the declaration), pervasive use of union types
       | (absl::Status/StatusOr are the open source versions) and, here's
       | the big one, individual teams were expressly forbidden from
       | creating their own templates.
       | 
       | Now compare this to Facebook's dialect: exceptions allowed,
       | mutable reference parameters allowed (side note: people weren't
       | strict with const-ifying reference parameters so you actually
       | didn't know if something was actually mutated or not), functions
       | that routinely just return bool (so helpful) and you can create
       | your own templates.
       | 
       | But seeing this post makes me see the wisdom in not only how cut
       | down Google's dialect is but also that stopping teams creating
       | their own templates is the only sane choice.
       | 
       | The depth of knowledge required to create templates that don't
       | behave unexpectedly (eg dangling references, redundant copying,
       | useable with move semantics, etc) is so large that only
       | specialists should engage in it.
       | 
       | There is a certain breed of programmer who will use a feature of
       | a language because it's there. They will view esoteric features,
       | unnecessary complexity and brevity over readability as not only
       | virtues but goals with which they can tell the world how smart
       | they are.
       | 
       | If you write code for you, you're either doing it alone or you're
       | not a team player. You write code for the next person who comes
       | along and has to figure out why it's broken or just how it works,
       | not to be as clever as you would like to think you are.
        
         | ruohola wrote:
         | > functions that routinely just return bool (so helpful)
         | 
         | I don't get it? What's wrong with returning a bool?
        
           | Kranar wrote:
           | There's this pretty abstract idea of boolean blindness, which
           | basically boils down to the idea that a boolean by itself
           | must always be associated with an interpretation and said
           | interpretation is external to the boolean. Afterall a boolean
           | by itself is just a single bit of data, 0 or 1, how to
           | interpret that bit is entirely independent of the bit itself.
           | 
           | This means anytime you operate on a boolean, you must somehow
           | recover its interpretation from somewhere, and the argument
           | is that such recovery is error prone and fragile.
           | 
           | The preferred way, presumably, is then to encode the
           | interpretation directly into the type, so for example you use
           | an enum along with pattern matching, or you write a type that
           | wraps a boolean with some value (like a Maybe/Optional type).
           | In effect anytime you have a boolean, you also carry with it
           | its interpretation side-by-side so you don't need to go
           | figuring out how to recover it.
           | 
           | This article goes into it in more depth:
           | 
           | https://existentialtype.wordpress.com/2011/03/15/boolean-
           | bli...
           | 
           | I personally think it's insightful and useful, but there are
           | also downsides to it as well, for example when you need to
           | operate on multiple booleans, it becomes unergonomic and
           | bloated to deal with pattern matching over multiple enums or
           | having to write out a lot of redundant code instead of
           | operating on boolean operators.
           | 
           | Basically consider these two options:
           | 
           | Option 1: boolean blindness.                   bool
           | isEven(int value);              ...
           | if(isEven(x)) {           print("Even");         } else {
           | print("Odd");         }
           | 
           | Option 2: Enum                   enum Parity {
           | EVEN,           ODD         };              Parity
           | getParity(int value);              ...
           | switch(getParity(x)) {           case: Parity::EVEN:
           | print("Even");             break;           case:
           | Parity::ODD:             print("Odd");             break;
           | }
           | 
           | You can decide which if the two options above is more
           | appealing to you in terms of reading and writing.
        
           | cletus wrote:
           | This applies to function parameters and return values: you
           | almost never want to use a bool. Instead you want to use an
           | enum with two values. Booleans are hard to read in most
           | cases. Obviously there are trivial cases where this isn't the
           | case (eg bool isDigit(char) is completely fine).
           | 
           | Contrived example:                   bool
           | connectToHost(string hostname, bool useSsl);
           | 
           | First problem: if it fails, why does it fail? Some will be
           | tempted to throw an exception. Better is to return some kind
           | of status.
           | 
           | Second problem: you add another version of SSL, now what? If
           | you'd used an enum, it's just another value. If not, you now
           | need to retrofit it.
           | 
           | Better version:                   absl::Status connect(string
           | hostname, EncryptionType encType);
           | 
           | People will often make mistakes when a function has 3 or more
           | booleans and put the wrong value in the wrong parameter. With
           | strongly typed arguments, this becomes a compiler error.
           | 
           | People will extend booleans to add a third value. In Java,
           | for example:                   Optional<Boolean> foo
           | 
           | But it doesn't end there. As I like to say, for when three
           | values for your boolean just aren't enough:
           | @nullable Optional<Boolean> foo
           | 
           | Just start with enums.
        
             | Psychlist wrote:
             | > People will often make mistakes when a function has 3 or
             | more ...
             | 
             | of anything. This is why non-compatible numeric subtypes
             | are so valuable. Code like "quantity_sold = price" should
             | not compile. You can do the same thing for other types
             | using the same template but IME that's somewhat less common
             | (but does happen: user_name = address!!).
             | 
             | It would be nice to get a variation on std::pair that works
             | in a similar way to Rust's std::result<value, error>,
             | because std::optional is just a dressed up boolean. I did
             | just swipe the std::pair declaration and do that, but
             | having it official would be nice. Especially for the non-
             | throwing version of the standard libraries.
        
             | dragonwriter wrote:
             | > People will often make mistakes when a function has 3 or
             | more booleans
             | 
             | A function with three or more positional parameters in a
             | language that isn't badly broken (that is, one that
             | supports keyword and/or structured parameters, which pretty
             | much all significant languages do) is, IMO, a code smell.
             | Even if more specific typing and IDE pulling up signatures
             | can makes it less likely to make usage errors, readability
             | is impaired.
        
         | UncleMeat wrote:
         | > individual teams were expressly forbidden from creating their
         | own templates
         | 
         | When were you at Google? I've been here a lot of years and
         | never ever heard this. My codebase has a fair amount of
         | templated code, including some metaprogramming magic. Nowhere
         | has any tool said "please don't do this", nor do I think it
         | should. Complex template code can be an absolute nightmare to
         | maintain, but there is a group of C++ experts that are
         | available to help if it is indeed the best solution to a
         | problem and you want to devise a maintainable implementation.
         | 
         | The closest in the style guide I can find is "Avoid complicated
         | template programming," which is clarified to include
         | metaprogramming magic. This is very different than what you
         | write and not even "forbidding" it.
        
           | cletus wrote:
           | 2010-2017
           | 
           | Certainly at that time, creating your own templates was
           | explicitly disallowed by the C++ style guide (ie readability
           | requirements). The public style guide mentions template meta-
           | programming specifically [1]:
           | 
           | > The techniques used in template metaprogramming are often
           | obscure to anyone but language experts. Code that uses
           | templates in complicated ways is often unreadable, and is
           | hard to debug or maintain.
           | 
           | This certainly applied to Google3. Non-Google3 C++ code bases
           | could and did have their own standards and style.
           | 
           | General note: templates were created but by library/framework
           | teams who specialized in that. The way I like to put it,
           | creating templates was a job for branch nodes not leaf nodes.
           | 
           | [1]: https://google.github.io/styleguide/cppguide.html#Templa
           | te_m...
        
             | pxx wrote:
             | This restricts metaprogramming, not you putting "template
             | <typename T>" in your code for a generic function. I don't
             | know how you got such a weird read of the readability
             | requirements; it is definitely not as strict as you put
             | here (and I'm currently at Google and commonly write C++).
        
             | UncleMeat wrote:
             | "Template meta-programming" and "templates" are very
             | different. Further, the style guide says "avoid" but does
             | not forbid it. Clang-Tidy doesn't throw up any warnings
             | when using things like std::enable_if.
             | 
             | My codebase overlaps with the majority of your tenure at
             | Google. We are in google3.
             | 
             | I do agree with the guidance that things like SFINAE should
             | be avoided in general, but I believe you've way overstated
             | the rigidity of the guidance.
        
             | petters wrote:
             | Could you possibly be misremembering?
             | 
             | I think creating e.g. template<F> F MyComputation(const F&
             | x) would be allowed e.g. for supporting both float and
             | double. It would also be required when using the Ceres
             | optimization library.
        
             | codeflo wrote:
             | I can't contribute to the discussion about Google's rules.
             | I just want to mention that simple uses of templates for
             | generic data structures are very different from template
             | meta programming. I can see how a style guide might allow
             | the former and ban the latter.
        
             | jeffbee wrote:
             | My C++ readability changelist contained a template. I don't
             | think this part of the style guide is what you thought it
             | was.
        
               | rpangrle wrote:
               | I'm a current Googler with C++ readability and I can
               | confirm, you're absolutely allowed to write templates in
               | "leaf node" projects and it's encouraged, especially in
               | cases where templated code reduces error-prone boiler
               | plate. Heck, there are whole Grow classes dedicated
               | around learning how to use variadic templates.
        
         | einpoklum wrote:
         | > They program in whatever subset of C++ their organization
         | allows
         | 
         | So, no-one writes C++ except for some organization that tightly
         | controls their work? :-( And no large organizations allow for
         | some coding autonomy in writing, say, the insides of libraries
         | and components?
         | 
         | > Google's C++ dialect
         | 
         | With changing language versions, dialects change. For example,
         | union types: With C++17 you have variants; which are still a
         | bit painful compared to other languages' union types, but are
         | usually an improvement over just using unions and crossing your
         | fingers you've always been careful with them.
         | 
         | > side note: this was a giant language fail that foo(f) could
         | be a const reference or a non-const reference and there's no
         | way to know without looking at the declaration
         | 
         | C and C++ have a lot of implicit type conversions. It's fair to
         | be against that, but it's not like this specific aspect is a
         | "giant fail" in itself; it makes sense, consistensy-wise.
         | 
         | > Facebook's dialect:
         | 
         | Those aspects you describe are indeed annoying, but, again -
         | are we talking about recent code?
         | 
         | > The depth of knowledge required to create templates that
         | don't behave unexpectedly ... is so large that only specialists
         | should engage in it.
         | 
         | I disagree. If you're not obviously careless, your templated
         | types will be reasonably well-behaved.
        
         | gjulianm wrote:
         | > here's the big one, individual teams were expressly forbidden
         | from creating their own templates.
         | 
         | What do you mean by this? General template code was forbidden
         | or just templated containers, STL style?
        
           | db48x wrote:
           | Means exactly what it says. You cannot create templated
           | functions, classes, etc.
        
             | gjulianm wrote:
             | That seems extremely restrictive. I get being careful
             | around heavy use of templates, and even more with
             | containers where allocation/copies/moves can be really
             | tricky; but there is a lot of space for using templates in
             | a simple but useful way.
        
               | pxx wrote:
               | These are allowed. I have no idea where the parent post
               | gets the idea that you can't ever write a template.
        
         | kllrnohj wrote:
         | > Personally I found Google's C++ dialect to be sane, even
         | pleasant. No exceptions,
         | 
         | Google's C++ dialect itself calls this out as a bug, not a
         | feature:
         | 
         | "On their face, the benefits of using exceptions outweigh the
         | costs, especially in new projects"
         | 
         | https://google.github.io/styleguide/cppguide.html#Exceptions
         | 
         | EDIT: Personally I like no exceptions normally but there's
         | definitely classes of problems where exceptions are
         | overwhelmingly superior, such as anything hitting files or a
         | wire (eg, IPC). Serialization code is incredibly tedious to do
         | error checking after every read or write call. This is where I
         | think the "throws" proposal strikes the right balance:
         | http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p070...
         | 
         | > and, here's the big one, individual teams were expressly
         | forbidden from creating their own templates.
         | 
         | There's no such rule. It just says avoid them if you can,
         | otherwise go for it:
         | https://google.github.io/styleguide/cppguide.html#Template_m...
         | 
         | And if there was such a rule, then Abseil wouldn't exist. You
         | don't end up with your own template library by telling people
         | to never write templates.
        
           | cletus wrote:
           | On exceptions, I respectfully disagree. Even if you don't use
           | exceptions in C++, just allowing them (and thus supporting
           | them) imposes a cost, both in terms of extra code but more
           | importantly on the programmer to make sure what they write is
           | exception-safe.
           | 
           | For a large number of people, exceptions is essentially
           | interchangeable with "output log message and exit".
           | 
           | > And if there was such a rule, then Abseil wouldn't exist.
           | 
           | You misunderstand me. What I call "leaf nodes" don't (or
           | shouldn't) create their own templates. By "leaf nodes" I
           | mean, say, the payments logging team. They're created by
           | specialists. Specifically, abseil is created from "//base",
           | which is a mature battle-tested set of libraries at this
           | point.
           | 
           | Likewise, anyone can create something in base or just modify
           | something that's there but any such addition or change is
           | going to go through an awful lot of scrutiny and testing.
           | 
           | That's the point.
        
             | kllrnohj wrote:
             | You don't start by building something general in a base
             | library. You start by solving your local problem, and if
             | that turns out to be a general problem it should then be
             | promoted to a base library. Battle-tested set of libraries
             | started out their life as random utilities in "leaf nodes"
             | - otherwise they wouldn't be "battle-tested". See also
             | https://blog.codinghorror.com/rule-of-three/
        
               | tsimionescu wrote:
               | Those are two well-known approaches to problem solving:
               | GP is proposing top-down, you're advocating for bottom-
               | up. There are pros and cons to each, and in the end it is
               | more of a matter of preferences.
               | 
               | Just to give an example of someone else advocating for
               | top-down problem solving, Bjarne advocates strongly for
               | designing the libraries that you will need before writing
               | specific code for your problem. He has some example
               | videos where he goes through a code review taking some
               | piece of procedural business code and showing how it
               | should have been written to take advantage of existing
               | libraries and creating new ones before.
        
         | hashingroll wrote:
         | > no mutable reference parameters
         | 
         | Sidenote: The style guide (recently?) removed the ban on non-
         | const references [0]. They are now allowed for non-optional
         | output parameters. Though returning value is generally
         | preferred over output parameters.
         | 
         | [0]
         | https://google.github.io/styleguide/cppguide.html#Inputs_and...
        
         | mgraczyk wrote:
         | > individual teams were expressly forbidden from creating their
         | own templates.
         | 
         | Just want to underscore what others are saying, that this is
         | not true and was not true during the time you claimed to work
         | there. I was at Google 2014-2016 and I'm there now. Templates
         | are common and not banned at all. I committed template-heavy
         | non-metaprogramming code to google3 in 2014 and also throughout
         | this year. I have never had C++ readability.
         | 
         | "Template Metaprogramming" is soft-banned in non-library code,
         | meaning that it is disallowed if the readability reviewer
         | looking at your code decides that what you are doing is
         | "metaprogramming".
         | 
         | There are other style guides that apply to small subsets of
         | google3, some of which forbid certain kinds of template
         | constructions (variadic, SFINAE, etc). Maybe you're thinking of
         | one of those? I'm not aware of any that forbid all templates.
        
         | kwertyoowiyop wrote:
         | L5's usually write code that needs L6's to maintain.
         | 
         | L7's should write code that only needs L4's to maintain.
        
           | cletus wrote:
           | I love this so much. This may be one of my favourite comments
           | ever.
           | 
           | Can I ask if this has a source? From a particular company?
           | Meme? Quote? Paraphrased from something?
        
             | Cthulhu_ wrote:
             | I know some versions of it, like Feynman saying that if he
             | can't explain it to a freshman, he doesn't understand it.
             | 
             | Likewise, if you write code that only you and someone
             | smarter than you can understand, you don't understand it.
             | 
             | That does bring a risk though. If you write simple code
             | (e.g. in Go) that does what it does without any trickery, a
             | more inexperienced job interviewer may look at it and scoff
             | because you're OBVIOUSLY not a very good developer if you
             | stick to simple code.
             | 
             | But that's a good litmus test, if they're like that, run
             | away. They don't write code to solve a problem, they write
             | code to flex and impress themselves, or to provide them
             | with job security, or CV boosts.
        
           | joebob42 wrote:
           | And l3s and l8s write code that needs l7s to maintain.
        
         | cjfd wrote:
         | I don't think picking some C++ dialect is wise. These features
         | are there for a reason. Funnily enough a lot of comments that
         | respond to this are all of the style 'yes, but nowadays google
         | allows this, o and this too, and that as well....' Sure, there
         | are things one should not do, like having raw pointers all over
         | the place and so on. Such things should be caught in code
         | review.
         | 
         | Actually, I totally hate the google style guide. The
         | prescriptions about indentation there seem to be optimized to
         | make the code as unreadable as possible. An indentation of only
         | two is already too little and adding that the opening brace is
         | at the end of the line it becomes very difficult to see what
         | block ends where.
        
           | emsy wrote:
           | Most languages get by with way fewer features and somehow
           | people still manage to write programs in them. If you ask 100
           | programmers which language has the worst feature creep, 99
           | will say C++ and maybe one person APL ;)
        
         | advael wrote:
         | Google's "dialect" both makes sense with other things I've
         | heard about working for them and makes working for them less
         | appealing. The flexible generic and compile-time resolution
         | paradigms offered by templates are a lot of the reason it's
         | compelling to use C++ over other languages, and while it's a
         | totally reasonable language to use for speed if you stick to
         | gluing together STL containers/algorithms, making anything
         | complicated under those rules sounds very unpleasant.
        
         | mysterydip wrote:
         | > It's well known that no one really programs in C++. They
         | program in whatever subset of C++ their organization allows,
         | their brain can handle or both.
         | 
         | Not to tangent too much but this is exactly how I see
         | javascript. I learned it one way, some code I need to use
         | learned it a different way, and I have to choose whether to
         | attempt to integrate it as-is, or spend the time to "port" it
         | to my understanding.
        
       | dataflow wrote:
       | It's never been necessary to use delete to make a class
       | uncopyable. It was always possible by just declaring (but not
       | defining) a private copy constructor/assignment. I'd still do the
       | same thing honestly, it's fewer keystrokes and not pointlessly
       | backwards-incompatible.
       | 
       | Better yet, for the majority of cases, just inherit from an
       | uncopyable class like boost::noncopyable.
        
         | kllrnohj wrote:
         | If you declare but don't define a private copy
         | constructor/assignment then you hit vague linker errors
         | elsewhere that will likely send a user on a chase trying to
         | figure out how their include paths don't match their linker
         | paths and which library they forgot to link against.
         | 
         | '= delete' makes it exceedingly clear that what they are doing
         | is not allowed, rather than "oh god dammit cmake what did I
         | miss now..."
         | 
         | Since '= deleted' was added in C++11, there's really not any
         | good "backwards-incompatible" arguments to be made about
         | avoiding it. C++11 support is extremely broad at this point and
         | has been for many, many years now.
        
           | dataflow wrote:
           | > If you declare but don't define a private copy
           | constructor/assignment then you hit vague linker errors
           | elsewhere that will likely send a user on a chase trying to
           | figure out how their include paths don't match their linker
           | paths and which library they forgot to link against.
           | 
           | I think you missed the importance of _private_. Users of it
           | won 't get it to compile for them to get a linker error.
        
         | jcranmer wrote:
         | A private copy constructor can still be copied in the class
         | itself. If you omit the definition, you still get a linker
         | error message, but linker errors are among the most obtuse to
         | actually discover. (Where did the copy construction actually
         | happen? Who knows! You get, at best, the function that called
         | it).
         | 
         | A deleted copy constructor produces better error messages. And
         | it's not really backwards-incompatible at this point--deleted
         | functions exist in compiler versions old enough to get a
         | COVID-19 vaccine.
        
           | dataflow wrote:
           | In theory yeah, in practice it's incredibly rare for a class
           | to look like it should be copyable to its own maintainer AND
           | for the maintainer to try to copy it from its own methods AND
           | for a linker error to be obscure for them to figure out when
           | they do their first debug build. In fact I'm not sure I've
           | _ever_ encountered this situation. Usually it 's pretty
           | obvious if your class should be copyable or not from the
           | outset so it's not common to make the mistake to begin with.
        
           | metiscus wrote:
           | Another worry is that an engineer will see the link error and
           | "fix it" instead of getting why it was done and diagnosing
           | the misuse of the class.
        
             | dataflow wrote:
             | I suppose this is possible for people who never programmed
             | C++ before C++11, I haven't really encountered this
             | incident to know. The biggest annoyance I've encountered
             | isn't a bug - rather, it's the annoying IDE warning that
             | the member is unimplemented!
        
         | gpderetta wrote:
         | > not pointlessly backwards-incompatible.
         | 
         | if the only reason for using the C++11 standard were the
         | =delete syntax, by all means, just use boost::noncopyable. But
         | if you are using features from C++11, then there is really no
         | reason for not using the new syntax.
        
         | Taywee wrote:
         | My original post: Private constructors still match for overload
         | resolution, and can cause your compiler to barf when a explicit
         | deletion would allow the compiler to find an appropriate legal
         | match.
         | 
         | I was wrong. delete leaves it in the overload set. I've been
         | using C++ for a decade and I'm still tripping over some of the
         | stupider semantics.
        
           | quietbritishjim wrote:
           | You edited before I got the chance to make a snarky reply :-)
           | For the record, the following snippet will not compile
           | because the deleted constructor will be matched during
           | overload resolution.                   class C {
           | public:             C(int) = delete;             C(long) {}
           | };                  int main() {             C x(3);
           | }
        
       | bendbro wrote:
       | I haven't seen this syntax before and I just knew it would be
       | c++.
        
       | admax88qqq wrote:
       | The longer I've been away from C++ the happier I've been.
        
       ___________________________________________________________________
       (page generated 2021-10-18 23:01 UTC)