[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] odd/move_semantics 5b1bde5d 1/5: Resurrect 'uncopyab
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] odd/move_semantics 5b1bde5d 1/5: Resurrect 'uncopyable_lmi.hpp' |
Date: |
Wed, 20 Jul 2022 19:50:36 -0400 (EDT) |
branch: odd/move_semantics
commit 5b1bde5d56b6aed87b2755f050ce1d5984c52ce6
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Resurrect 'uncopyable_lmi.hpp'
Resurrected thus:
git checkout fd2c4e65d8~1 -- uncopyable_lmi.hpp
and modified just enough to pass the concinnity test.
Although outmoded, this code isn't wrong. Even if it isn't used again
as such, its documentation remains valuable.
---
uncopyable_lmi.hpp | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)
diff --git a/uncopyable_lmi.hpp b/uncopyable_lmi.hpp
new file mode 100644
index 00000000..a3cc2667
--- /dev/null
+++ b/uncopyable_lmi.hpp
@@ -0,0 +1,124 @@
+// Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2022 Gregory
W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// https://savannah.nongnu.org/projects/lmi
+// email: <gchicares@sbcglobal.net>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#ifndef uncopyable_lmi_hpp
+#define uncopyable_lmi_hpp
+
+#include "config.hpp"
+
+#include <type_traits>
+
+/// Forbid compiler to generate copy and assignment functions.
+///
+/// This implementation is an original work. The idea of a mixin with
+/// private copy and assignment members is very old and of uncertain
+/// provenance. The idea of making that mixin a template seems to have
+/// been suggested first by Cacciola:
+/// http://lists.boost.org/Archives/boost/2001/09/16912.php
+/// http://lists.boost.org/Archives/boost/2001/09/17385.php
+///
+/// This class is often seen in a non-template guise, but consider:
+///
+/// class B0 : private Uncopyable {};
+/// class B1 : private Uncopyable {};
+/// class D : public B0, public B1 {};
+///
+/// The derived class has two distinct copies of Uncopyable, to which
+/// the empty base class optimization cannot be applied:
+///
http://groups.google.com/group/comp.lang.c++.moderated/msg/6cc884d20b336d08
+/// Rewriting that example to use virtual inheritance:
+///
+/// class B0 : virtual private Uncopyable {};
+/// class B1 : virtual private Uncopyable {};
+/// class D : public B0, public B1 {};
+///
+/// is likely to introduce its own efficiency issues:
+/// http://lists.boost.org/Archives/boost/2001/09/17391.php
+///
+/// Even where such inefficiencies don't matter, the template version
+/// is preferable for its clarity. Consider:
+///
+// class Uncopyable /* non-template implementation */;
+/// class B0 : private Uncopyable {};
+/// class B1 : private Uncopyable {};
+/// class D : private Uncopyable, public B0, public B1 {};
+///
+/// Deriving class D explicitly from Uncopyable serves two purposes:
+/// it prevents the compiler from implicitly defining a copy ctor or
+/// a copy assignment operator; and it also documents that the lack of
+/// explicit declarations for those special member functions is not an
+/// oversight. As self-enforcing documentation, it belongs in class D.
+/// However, this example is likely to elicit an ambiguity warning--a
+/// Bad Thing when one strives to write code that compiles without any
+/// warnings.
+///
+/// Such warnings may be avoided by virtual inheritance, as in the
+/// second example above--though that's inefficient, as already noted.
+/// It's also not ideal for documenting the derived class, because
+/// 'virtual' belongs in the base classes:
+/// http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9
+/// Adding a new class later, e.g.:
+/// class E : private Uncopyable, public D {};
+/// would require changing D's inheritance to virtual, yet D and E are
+/// likely to be declared in different source files.
+///
+/// The present class does requires a template parameter (which is
+/// reasonably constrained to name the class rendered uncopyable):
+///
+/// class B0 : private uncopyable<B0> {};
+/// class B1 : private uncopyable<B1> {};
+/// class D : private uncopyable<D>, public B0, public B1 {};
+///
+/// but its clarity and efficiency make it the least objectionable
+/// option.
+
+namespace lmi
+{
+template<typename T>
+class uncopyable
+{
+ protected:
+ uncopyable() = default;
+ ~uncopyable()
+ {
+ static_assert(std::is_base_of<uncopyable<T>,T>::value, "");
+ }
+
+ private:
+ uncopyable(uncopyable const&);
+ uncopyable& operator=(uncopyable const&);
+};
+} // namespace lmi
+
+// If lmi provided unit tests that deliberately fail to compile, then
+// this could be used:
+//
+// #include "uncopyable_lmi.hpp"
+//
+// class X : private lmi::uncopyable<X> {};
+//
+// int main()
+// {
+// X x;
+// X y(x); // Error: cannot copy.
+// x = y; // Error: cannot assign.
+// }
+
+#endif // uncopyable_lmi_hpp
+