Boost logo

Boost :

From: David Bergman (davidb_at_[hidden])
Date: 2006-07-23 20:15:57


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk