
Beman wrote:
* Addition of a header boost/identifier.hpp. For years I've used a similar class to provide the type safety and freedom from unwanted conversions that is missing when a simple int is used for an identifier. This is logically separate from the system stuff, but for convenience is included in the system package since error_code.hpp uses it.
I like the idea of having such a (meta) construct in my programming portfolio, much like the "newtype" in Haskell, which introduces an isomorphic type. A few comments: 1. You are right in that it is separate, and should definitely be separate from the error code stuff; actually, since it is a construct mapping types to types - i.e., a meta function - it might even find its proper home in MPL :-) 2. As someone else pointed out, even though this functor establishing homorphic types is useful for the use case of having identifiers, it should not stop there. Thus, its name should reflect that wider scope, such as "homorphic_type." Ok, more pragmatic then: "embed_type." [hope that going from a adjective to a verb did not tick anyone off] 3. I see a few distinct types of homomorphisms here, which should correspond to policies: (i) order (ii) equivalence (iii) assignability (iv) conversion (to source) I implemented them as individual policy links that are then chained together explicitly. Will use a hierarchy generator, such as Loki's, or create a chaining construct with the help of MPL and upload it to the vault. I could not access the file vault, but will upload it later. Till then, I attach the header in the bottom of this file. First, a tiny sample where one can play with the policy flags a bit - such as turning off conversion. /* File: test_embed_type.hpp Author: David Bergman Date: 2006-07-25 This is a simple test of the 'embed_type' proposal, which is actually just a slightly decoupled (policy-wise) and more generic version of Beman Daves' "identifier" proposal. */ #include <iostream> #include <boost/embed_type.hpp> // We include Beam Daves' identifier here as a special case template <typename T, D> class identifier : public boost::embed_type<int, CustomerId, true, // preserve order true, // preserve equivalence false, // cannot assign from embedded type false // cannot convert to embedded type > {}; class CustomerId : public boost::embed_type<int, CustomerId, true, // order true, // equivalence true, // assignability true // conversion to embedded > { public: CustomerId() {} // Ugh, GCC does not support mentioning only the template // name for sub classes :-(, so we use assignment instead... CustomerId(int num) { value_ref(num); } }; int main(int argc, const char* argv[]) { CustomerId id = 42; int idNum = id; std::cout << "Id is CustomerId(" << id << ") or int(" << idNum << ")" << std::endl; } Ok, now the header itself (yes, I should include proper copyright markers etc.) #ifndef EMBED_TYPE_HPP #define EMBED_TYPE_HPP namespace boost { /* File: embed_type.hpp Author: David Bergman, based on Beman Daves' 'identifier' proposal. Date: 2006-07-25 These templates and classes embed a (primitive or not) type, and with a set of policies decides what aspects of that type should be exposed in the embedding. TODO: use MPL (or similar meta techniques) to build the chain of policies in compile-time. NOTE TO MYSELF: implement such a hierarchy generator using MPL. */ /* The various policies that we use in the final embedding. The policies are either implemented or not, depending on a template flag. They constitute an inheritance chain of types. We could generate a hierarchy with a meta generator such as Loki's GenScatterHierarchy, also allowing for totally new embedding aspects, instead of this explicit chaining of enabled of disabled policies. The template parameter D signifies the embedding type while the C parameter is the current bottom of chain. */ // Order template <typename T, typename D, bool implement, typename C> class embed_order : public C { public: // The "this->" is needed since GCC 3.4 (and the C++ standard...) will // not find the names from the template parameters bool operator<(const D& rhs) const { return this->value_ref() < rhs.value_ref(); } bool operator<=(const D& rhs) const { return this->value_ref() <= rhs.value_ref(); } bool operator>(const D& rhs) const { return this->value_ref() > rhs.value_ref(); } bool operator>=(const D& rhs) const { return this->value_ref() >= rhs.value_ref(); } }; template <typename T, typename D, typename C> class embed_order<T, D, false, C> : public C {}; // Equivalence template <typename T, typename D, bool implement, typename C> class embed_equivalence : public C { public: bool operator==(const D& rhs) const { return this->value_ref() == rhs.value_ref(); } bool operator!=(const D& rhs) const { return this->value_ref() != rhs.value_ref(); } }; template <typename T, typename D, typename C> class embed_equivalence<T, D, false, C> : public C {}; // Assignability template <typename T, typename D, bool implement, typename C> class embed_assignability : public C { public: D& operator=(const D& rhs) { this->value_ref(rhs.value_ref()); return *this; } }; template <typename T, typename D, typename C> class embed_assignability<T, D, false, C> : public C {}; // Conversion to source template <typename T, typename D, bool implement, typename C> class embed_conversion : public C { public: operator T() const { return this->value_ref(); } }; template <typename T, typename D, typename C> class embed_conversion<T, D, false, C> : public C {}; /* The structure-holding type */ template <typename T> class embed_structure { protected: embed_structure() {}; embed_structure(T m_value) : m_value(m_value) {} public: T value() const { return m_value; } protected: void value_ref(const T& value) { m_value = value; } T& value_ref() { return m_value; } const T& value_ref() const { return m_value; } private: T m_value; }; /* The (conglomerate) embedding itself. Painfully linking the type chain... */ template<typename T, typename D, bool embedOrder = true, bool embedEquivalence = true, bool embedAssignability = true, bool embedConversion = true > class embed_type : public embed_order<T, D, embedOrder, embed_equivalence<T, D, embedEquivalence, embed_assignability<T, D, embedAssignability, embed_conversion<T, D, embedConversion, embed_structure<T> > > > > { protected: embed_type() {} embed_type(T value) : embed_structure<T>(value) {}; }; } // namespace boost #endif