3 ms·
Why does C++ think my class is copy-constructible when it can't be?
- kazinator 1y agoThis whole article is a very verbose way to reach the conclusion that std::is_copy_constructible_v is a poorly chosen name, not reflecting the actual truth that the construct provides. If it were called std::has_copy_constructor, there would be no need to write even the title of this article, let alone the body. Also, maybe this should require a diagnostic due to it being statically obvious that it is calling a deleted constructor: Derived(Derived const& d) : Base<T>(d) {} ... and if we use regular non-template classes, it does! Clang: #include <type_traits> struct Base { // Default-constructible Base() = default; // Not copy-constructible Base(Base const &) = delete; }; struct Derived : Base { Derived() = default; Derived(Derived const& d) : Base(d) { } }; Clang: copy-constructor.cc:15:33: error: call to deleted constructor of 'Base' 15 | Derived(Derived const& d) : Base(d) { } | ^ ~ copy-constructor.cc:9:5: note: 'Base' has been explicitly marked deleted here 9 | Base(Base const &) = delete; | ^ 1 error generated. If the program requires a diagnostic which allows it to be rejected entirely, it then doesn't matter what is_copy_constructible returned. The only reason we don't get a diagnostic is that the language plays it loose with templates, in many cases deferring type checks until instantiation. It is possible to argue that is_copy_constructible isn't necessarily badly named, but rather foiled by templates.
- unddoch 1y agoIt wouldn't be the same trait, for example https://stackoverflow.com/questions/43606777/why-is-class-with-non-const-copy-constructor-not-treated-as-copy-constructible https://stackoverflow.com/questions/43606777/why-is-class-wi...
- kazinator 1y agoYou mean, it still wouldn't be an accurate name? Maybe has_const_copy_constructor?
- unddoch 1y agoI guess it's better, but with C++ being C++, you will then need to decide if you consider struct A { A(const volatile& A); }; as a class with a const copy constructor. Maybe someone cares? Proper templated classes don't behave like this. If you manually define a copy constructor in a template class it has to work. And if it works only conditionally (like in many container classes) you need to add constraints on your constructors (>C++20) or derive from appropriately specialized base classes (e.g. std::_Optional_base in libstdc++). It sucks to tell users "you're holding it wrong", but I don't think there's a way to make it simpler without breaking everything written since C++11.
- kazinator 1y agoThe extra qualification doesn't prevent it from taking const objects, so ...
- celrod 1y agoI agree. The problem with eager diagnostics and templates is that the program could define a `Base<int>` specialization that has a working copy constructor later. [0] I think if you define an explicit instantiation definition, it should type check at that point and error. [1] I find myself sometimes defining explicit instantiations to make clangd useful (can also help avoid repeated instantiations if you use explicit declarations in other TUs). [0] https://en.cppreference.com/w/cpp/language/template_specialization.html https://en.cppreference.com/w/cpp/language/template_speciali... [1] https://en.cppreference.com/w/cpp/language/class_template.html https://en.cppreference.com/w/cpp/language/class_template.ht...
- muststopmyths 1y agoI would argue that has_copy_constructor would also have the same issue in naming since most people would assume that has_copy_constructor means the damn thing works for copying. Too many traits is my diagnosis, so I agree with "foiled by templates". Like almost any attempt to make a sane C++ codebase.
- HelloNurse 1y ago> most people would assume that has_copy_constructor means the damn thing works for copying Assumptions that something "works" in C++ are generally too nuanced and optimistic to be a good idea. Calling the test "has_copy_constructor" would at least make explicit that it is a test about what declarations a class contains, which is a very rough compile-time approximation of being copy-constructible in practice: a valid declaration is only the first step towards calling a constructor without runtime errors and other trouble.
- quuxplusone 1y ago> If it were called std::has_copy_constructor, there would be no need to write even the title of this article Ah, but then someone might ask "Why does the library report that my type has no copy constructor, when it is in fact copyable?" And then the blog post would have to be about how it's possible for a type to be copy-constructed using a constructor (or constructor template) that is not itself a copy constructor. Of course, the existing state of C++ doesn't prevent us from having to write that blog post, either!
- keybored 1y agoSometimes C++ let’s me read a Raymond Chen article. Which is nice of it.
- curtisszmania 1y ago[dead]
- rramadass 1y agoThe article points out this; The rule for determining copy constructibility is whether a non-deleted copy constructor is present. In the case of Derived, it is present. It may not be instantiatable, but that’s not what is_copy_constructible looks for. That is what you need to know.
- HelloNurse 1y agoIt's the best that a compiler can be reasonably expected to do.
- revskill 1y ago[flagged]
- deleted 1y ago[deleted]
- etbebl 1y agoThe real wtf here is templates, right? Am I right in thinking that if Derived wasn't a template, its copy constructor that tries to use a deleted parent copy constructor would fail to compile?
- lisper 1y agoAnswered here: https://news.ycombinator.com/item?id=44236227 https://news.ycombinator.com/item?id=44236227
- rich_sasha 1y agoI used to code C++ in early 00s and used to think I know the language OK. Then I stopped using it, meanwhile C++11 and friends came, along with lambda syntax, move semantics etc. - that was a jump but I could still just about follow. Now I don't follow anymore. It's a new language on top of new language on top of new language. On top of C++. On top of C.
- dh2022 1y agoI have the same feeling. It seems to me these copy/move semantics are done for performance reasons, and at the same time are very hard to follow / use / implement correctly. Today I would rather use C or assembly language than C++. At least I know what I am doing.
- Night_Thastus 1y agoC++11 introduces a lot of things that make it far, far easier to work with. I would not want to go back to a pre-11 environment. As for everything after that, you don't need to use those features. You can still write C++ like it's '11 and be none the lesser. That's what I do. Keep it simple.
- addaon 1y ago
- calmbonsai 1y agoC++ is the language you get when the design praxis is "yes to everything". It was my "daily driver" in the late '90s, but I would never touch it again outside of specific domains such as gaming.