lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [4776] Refactor (VS)


From: Greg Chicares
Subject: [lmi-commits] [4776] Refactor (VS)
Date: Wed, 24 Feb 2010 19:04:24 +0000

Revision: 4776
          http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=4776
Author:   chicares
Date:     2010-02-24 19:04:23 +0000 (Wed, 24 Feb 2010)
Log Message:
-----------
Refactor (VS)

Modified Paths:
--------------
    lmi/trunk/ChangeLog
    lmi/trunk/mc_enum.hpp
    lmi/trunk/mc_enum.tpp
    lmi/trunk/mc_enum_aux.hpp
    lmi/trunk/mc_enum_fwd.hpp
    lmi/trunk/mc_enum_test.cpp
    lmi/trunk/mc_enum_test_aux.cpp
    lmi/trunk/mc_enum_test_aux.hpp
    lmi/trunk/mc_enum_types.cpp
    lmi/trunk/mc_enum_types.hpp
    lmi/trunk/mc_enum_types_aux.cpp
    lmi/trunk/yare_input.cpp

Added Paths:
-----------
    lmi/trunk/mc_enum_metadata.hpp

Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/ChangeLog 2010-02-24 19:04:23 UTC (rev 4776)
@@ -24353,8 +24353,24 @@
   mc_enum_test.cpp
 Improve documentation.
 
- <address@hidden> [762]
+20100224T0302Z <address@hidden> [762]
 
   version.hpp
 Mark release candidate.
 
+20100224T1904Z <address@hidden> [762]
+
+  mc_enum.hpp
+  mc_enum.tpp
+  mc_enum_aux.hpp
+  mc_enum_fwd.hpp
+  mc_enum_metadata.hpp [new file]
+  mc_enum_test.cpp
+  mc_enum_test_aux.cpp
+  mc_enum_test_aux.hpp
+  mc_enum_types.cpp
+  mc_enum_types.hpp
+  mc_enum_types_aux.cpp
+  yare_input.cpp
+Refactor (VS).
+

Modified: lmi/trunk/mc_enum.hpp
===================================================================
--- lmi/trunk/mc_enum.hpp       2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum.hpp       2010-02-24 19:04:23 UTC (rev 4776)
@@ -21,18 +21,6 @@
 
 // $Id$
 
-// Acknowledgment
-//
-// The valuable idea of associating immutable arrays with this class
-// as non-type template parameters was taken from an article in
-// comp.lang.c++.moderated by Hyman Rosen <address@hidden>,
-// archived at
-//   http://groups.google.com/groups?selm=t7aeqycnze.fsf%40calumny.jyacc.com
-// which bears no copyright notice, as is usual in usenet. This
-// implementation descends from work GWC did in 1998, which predates
-// that article; any defect here should not reflect on Hyman Rosen's
-// reputation.
-
 #ifndef mc_enum_hpp
 #define mc_enum_hpp
 
@@ -44,7 +32,7 @@
 #include <boost/static_assert.hpp>
 #include <boost/type_traits.hpp>
 
-#include <cstddef>
+#include <cstddef> // std::size_t
 #include <deque>
 #include <string>
 #include <vector>
@@ -102,57 +90,22 @@
 /// those types explicitly in that one translation unit, in order to
 /// avoid bloat.
 ///
-/// Careful attention to detail enables compile-time checking of the
-/// sizes of the arrays used as non-type parameters. If too many
-/// initializers are given, the compiler must emit a diagnostic
-/// [8.5.1/6]. Supplying too few is acceptable [8.5.1/7] to the
-/// language, but likely to cause run-time errors--which can be
-/// turned into compile-time errors by the technique presented here.
-///
-/// Specific types require one translation unit (TU) for the
-/// instantiation and a header to make them available to other TUs.
-///
-/// The header should have a typedef declaration, which requires
-/// declarations of the arrays used as non-type arguments. Those array
-/// declarations must specify bounds explicitly, because an array of
-/// unknown bound is an incomplete type that prevents instantiation of
-/// the class template--and initializers must not be specified in the
-/// header, because including it in two TUs would violate the ODR.
-///
-/// The instantiation TU, however, should omit the bound specifiers,
-/// causing the bounds to be 'calculated' [8.3.4/3]. Passing them as
-/// non-type arguments, as '(&array)[n]' rather than as 'array[n],
-/// then causes explicit instantiation to fail if the calculated
-/// bounds do not match the size explicitly specified as a template
-/// parameter. Limitation: this safeguard is ineffective for a TU
-/// other than the instantiation TU that includes both the header and
-/// the code in the accompanying '.tpp' file that implements the
-/// template class, because implicit instantiation would occur; but
-/// that is easily avoided in the physical design.
-///
-/// Because both the header and the instantiation TU require the
-/// definition of the underlying enum type, that type must be defined
-/// in a separate header that both these files include.
-///
-/// The same benefit could be realized through consistent use of a
-/// macro. This built-in approach is preferred because it avoids using
-/// the preprocessor and its compile-time checking is automatic.
+/// Metadata is deliberately excluded from this header, for reasons
+/// explained in the documentation for class mc_enum_data.
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+template<typename T>
 class mc_enum
     :public mc_enum_base
-    ,private boost::equality_comparable<mc_enum<T,n,e,c>, mc_enum<T,n,e,c> >
-    ,private boost::equality_comparable<mc_enum<T,n,e,c>, T>
-    ,private boost::equality_comparable<mc_enum<T,n,e,c>, std::string>
+    ,private boost::equality_comparable<mc_enum<T>, mc_enum<T> >
+    ,private boost::equality_comparable<mc_enum<T>, T          >
+    ,private boost::equality_comparable<mc_enum<T>, std::string>
 {
     BOOST_STATIC_ASSERT(boost::is_enum<T>::value);
-    BOOST_STATIC_ASSERT(0 < n);
 
     friend class mc_enum_test;
 
   public:
     typedef T enum_type;
-    enum{Cardinality = n};
 
     mc_enum();
     explicit mc_enum(T);
@@ -161,8 +114,8 @@
     mc_enum& operator=(T);
     mc_enum& operator=(std::string const&);
 
-    bool operator==(mc_enum<T,n,e,c> const&) const;
-    bool operator==(T) const;
+    bool operator==(mc_enum<T>  const&) const;
+    bool operator==(T                 ) const;
     bool operator==(std::string const&) const;
 
     static std::size_t ordinal(std::string const&);
@@ -178,6 +131,10 @@
     static std::vector<std::string> const& all_strings();
 
   private:
+    static std::size_t        n();
+    static T    const*        e();
+    static char const* const* c();
+
     // datum_base required implementation.
     // TODO ?? Consider moving the implementation into the base class.
     virtual std::istream& read (std::istream&);

Modified: lmi/trunk/mc_enum.tpp
===================================================================
--- lmi/trunk/mc_enum.tpp       2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum.tpp       2010-02-24 19:04:23 UTC (rev 4776)
@@ -22,6 +22,7 @@
 // $Id$
 
 #include "mc_enum.hpp"
+#include "mc_enum_metadata.hpp"
 
 #include "alert.hpp"
 #include "facets.hpp"
@@ -30,55 +31,71 @@
 #include <algorithm> // std::find()
 #include <typeinfo>
 
-// TODO ?? Should there be a runtime check that all elements in 'e'
-// and in 'c' are unique? Can that be asserted at compile time?
+// TODO ?? Should there be a runtime check that all elements in
+// e() and in c() are unique? Can that be asserted at compile time?
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-mc_enum<T,n,e,c>::mc_enum()
-    :mc_enum_base(n)
-    ,value_(e[0])
-{}
+template<typename T>
+std::size_t        mc_enum<T>::n() {return mc_enum_key<T>::n_;}
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-mc_enum<T,n,e,c>::mc_enum(T t)
-    :mc_enum_base(n)
+template<typename T>
+T    const*        mc_enum<T>::e() {return mc_enum_key<T>::e();}
+
+template<typename T>
+char const* const* mc_enum<T>::c() {return mc_enum_key<T>::c();}
+
+/// The header that defines class mc_enum is by design unaware of its
+/// associated metadata, so static assertions that depend on metadata
+/// are written here.
+
+template<typename T>
+mc_enum<T>::mc_enum()
+    :mc_enum_base(n())
+    ,value_(e()[0])
+{
+    typedef mc_enum_key<T> metadata;
+    BOOST_STATIC_ASSERT(0 < metadata::n_);
+}
+
+template<typename T>
+mc_enum<T>::mc_enum(T t)
+    :mc_enum_base(n())
     ,value_(t)
 {}
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-mc_enum<T,n,e,c>::mc_enum(std::string const& s)
-    :mc_enum_base(n)
-    ,value_(e[ordinal(s)])
+template<typename T>
+mc_enum<T>::mc_enum(std::string const& s)
+    :mc_enum_base(n())
+    ,value_(e()[ordinal(s)])
 {}
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-mc_enum<T,n,e,c>& mc_enum<T,n,e,c>::operator=(T t)
+template<typename T>
+mc_enum<T>& mc_enum<T>::operator=(T t)
 {
     value_ = t;
     return *this;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-mc_enum<T,n,e,c>& mc_enum<T,n,e,c>::operator=(std::string const& s)
+template<typename T>
+mc_enum<T>& mc_enum<T>::operator=(std::string const& s)
 {
-    value_ = e[ordinal(s)];
+    value_ = e()[ordinal(s)];
     return *this;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-bool mc_enum<T,n,e,c>::operator==(mc_enum<T,n,e,c> const& z) const
+template<typename T>
+bool mc_enum<T>::operator==(mc_enum<T> const& z) const
 {
     return z.value_ == value_;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-bool mc_enum<T,n,e,c>::operator==(T t) const
+template<typename T>
+bool mc_enum<T>::operator==(T t) const
 {
     return t == value_;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-bool mc_enum<T,n,e,c>::operator==(std::string const& s) const
+template<typename T>
+bool mc_enum<T>::operator==(std::string const& s) const
 {
     return s == str();
 }
@@ -108,43 +125,43 @@
 }
 } // Unnamed namespace.
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::istream& mc_enum<T,n,e,c>::read(std::istream& is)
+template<typename T>
+std::istream& mc_enum<T>::read(std::istream& is)
 {
     std::locale old_locale = is.imbue(blank_is_not_whitespace_locale());
     std::string s;
     is >> s;
     is.imbue(old_locale);
 
-    std::size_t v = std::find(c, c + n, s) - c;
-    if(n == v)
+    std::size_t v = std::find(c(), c() + n(), s) - c();
+    if(n() == v)
         {
-        v = std::find(c, c + n, provide_for_backward_compatibility(s)) - c;
+        v = std::find(c(), c() + n(), provide_for_backward_compatibility(s)) - 
c();
         }
-    if(n == v)
+    if(n() == v)
         {
         ordinal(s); // Throws.
         throw "Unreachable.";
         }
-    value_ = e[v];
+    value_ = e()[v];
 
     return is;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::ostream& mc_enum<T,n,e,c>::write(std::ostream& os) const
+template<typename T>
+std::ostream& mc_enum<T>::write(std::ostream& os) const
 {
     return os << str();
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::size_t mc_enum<T,n,e,c>::cardinality() const
+template<typename T>
+std::size_t mc_enum<T>::cardinality() const
 {
-    return n;
+    return n();
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-void mc_enum<T,n,e,c>::enforce_proscription()
+template<typename T>
+void mc_enum<T>::enforce_proscription()
 {
     if(is_allowed(ordinal()))
         {
@@ -154,15 +171,15 @@
     std::size_t z = first_allowed_ordinal();
     if(z < cardinality())
         {
-        value_ = e[z];
+        value_ = e()[z];
         }
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::size_t mc_enum<T,n,e,c>::ordinal() const
+template<typename T>
+std::size_t mc_enum<T>::ordinal() const
 {
-    std::size_t i = std::find(e, e + n, value_) - e;
-    if(i == n)
+    std::size_t i = std::find(e(), e() + n(), value_) - e();
+    if(i == n())
         {
         fatal_error()
             << "Value "
@@ -176,23 +193,23 @@
     return i;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::string mc_enum<T,n,e,c>::str(int j) const
+template<typename T>
+std::string mc_enum<T>::str(int j) const
 {
-    return c[j];
+    return c()[j];
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-T mc_enum<T,n,e,c>::value() const
+template<typename T>
+T mc_enum<T>::value() const
 {
     return value_;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::size_t mc_enum<T,n,e,c>::ordinal(std::string const& s)
+template<typename T>
+std::size_t mc_enum<T>::ordinal(std::string const& s)
 {
-    std::size_t v = std::find(c, c + n, s) - c;
-    if(v == n)
+    std::size_t v = std::find(c(), c() + n(), s) - c();
+    if(v == n())
         {
         fatal_error()
             << "Value '"
@@ -206,16 +223,16 @@
     return v;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::string mc_enum<T,n,e,c>::str() const
+template<typename T>
+std::string mc_enum<T>::str() const
 {
-    return c[ordinal()];
+    return c()[ordinal()];
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
-std::vector<std::string> const& mc_enum<T,n,e,c>::all_strings()
+template<typename T>
+std::vector<std::string> const& mc_enum<T>::all_strings()
 {
-    static std::vector<std::string> const v(c, c + n);
+    static std::vector<std::string> const v(c(), c() + n());
     return v;
 }
 

Modified: lmi/trunk/mc_enum_aux.hpp
===================================================================
--- lmi/trunk/mc_enum_aux.hpp   2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_aux.hpp   2010-02-24 19:04:23 UTC (rev 4776)
@@ -31,13 +31,13 @@
 #include <string>
 #include <vector>
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+template<typename T>
 std::vector<std::string> mc_e_vector_to_string_vector
-    (std::vector<mc_enum<T,n,e,c> > const& ve
+    (std::vector<mc_enum<T> > const& ve
     )
 {
     std::vector<std::string> vs;
-    typename std::vector<mc_enum<T,n,e,c> >::const_iterator ve_i;
+    typename std::vector<mc_enum<T> >::const_iterator ve_i;
     for(ve_i = ve.begin(); ve_i != ve.end(); ++ve_i)
         {
         vs.push_back(ve_i->str());

Modified: lmi/trunk/mc_enum_fwd.hpp
===================================================================
--- lmi/trunk/mc_enum_fwd.hpp   2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_fwd.hpp   2010-02-24 19:04:23 UTC (rev 4776)
@@ -26,9 +26,7 @@
 
 #include "config.hpp"
 
-#include <cstddef> // std::size_t
-
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+template<typename T>
 class mc_enum;
 
 #endif // mc_enum_fwd_hpp

Added: lmi/trunk/mc_enum_metadata.hpp
===================================================================
--- lmi/trunk/mc_enum_metadata.hpp                              (rev 0)
+++ lmi/trunk/mc_enum_metadata.hpp      2010-02-24 19:04:23 UTC (rev 4776)
@@ -0,0 +1,124 @@
+// Metadata for string-Mapped, value-Constrained Enumerations.
+//
+// Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+// Acknowledgment
+//
+// The valuable idea of associating immutable arrays with a class
+// as non-type template parameters was taken from an article in
+// comp.lang.c++.moderated by Hyman Rosen <address@hidden>,
+// archived at
+//   http://groups.google.com/groups?selm=t7aeqycnze.fsf%40calumny.jyacc.com
+// which bears no copyright notice, as is usual in usenet. This
+// implementation descends from work GWC did in 1998, which predates
+// that article; any defect here should not reflect on Hyman Rosen's
+// reputation.
+
+#ifndef mc_enum_metadata_hpp
+#define mc_enum_metadata_hpp
+
+#include "config.hpp"
+
+#include <boost/static_assert.hpp>
+
+#include <cstddef> // std::size_t
+
+/// Associate an mc_enum type with its metadata through its enum type.
+///
+/// This class template is intended to be specialized for each type,
+/// each specialization deriving from class mc_enum_data.
+
+template<typename T>
+struct mc_enum_key
+{};
+
+/// Metadata for class template mc_enum.
+///
+/// Careful attention to detail enables compile-time checking of the
+/// sizes of the arrays used as non-type parameters. If too many
+/// initializers are given, the compiler must emit a diagnostic
+/// [8.5.1/6]. Supplying too few is acceptable [8.5.1/7] to the
+/// language, but likely to cause run-time errors--which can be
+/// turned into compile-time errors by the technique presented here.
+///
+/// Specific types require one translation unit (TU) for the
+/// instantiation and a header to make them available to other TUs.
+///
+/// The header should define a mc_enum_key specialization that derives
+/// from this struct; that requires declarations of the arrays used as
+/// non-type arguments. Those array declarations must specify bounds
+/// explicitly, because an array of unknown bound is an incomplete
+/// type that prevents instantiation of class template mc_enum_data.
+/// However, the header must not specify array initializers, because
+/// including it in two TUs would violate the ODR.
+///
+/// The instantiation TU, however, should omit the bound specifiers,
+/// causing the bounds to be 'calculated' [8.3.4/3]. Passing them as
+/// non-type arguments, as '(&array)[n]' rather than as 'array[n],
+/// then causes explicit instantiation to fail if the calculated
+/// bounds do not match the size explicitly specified as a template
+/// parameter. Limitation: this safeguard is ineffective for a TU
+/// other than the instantiation TU that includes both the header and
+/// the code in the accompanying '.tpp' file that implements the
+/// class template, because implicit instantiation would occur; but
+/// that is easily avoided in the physical design.
+///
+/// Because both the header and the instantiation TU require the
+/// definition of the underlying enum type, that type must be defined
+/// in a separate header that both these files include.
+///
+/// The same benefit could be realized through consistent use of a
+/// macro. This built-in approach is preferred because it avoids using
+/// the preprocessor and its compile-time checking is automatic.
+///
+/// It is contemplated that this class template will be instantiated
+/// to create numerous types in one translation unit for use in other
+/// translation units. Given that usage, it makes sense to instantiate
+/// those types explicitly in that one translation unit, in order to
+/// avoid bloat.
+///
+/// Implementation notes.
+///
+/// Array arguments are adjusted to pointers [14.1/8].
+///
+/// e() and c() could have been provided as static data members.
+/// However, they're both pointers, so they can't be used in ICEs, in
+/// particular as constant-initializers within the struct definition;
+/// and writing them outside the struct definition would be balky.
+///
+/// 'n' could have been provided as a function rather than a constant,
+/// but a constant is preferable because it can be used in an ICE. It
+/// could have been an enumeration, but declaring it as a std::size_t
+/// costs no more and makes its type definite and explicit.
+
+template<typename T, std::size_t N, T const (&E)[N], char const*const (&C)[N]>
+struct mc_enum_data
+{
+    BOOST_STATIC_ASSERT(0 < N);
+
+    static std::size_t const n_ = N;
+    static T    const*        e() {return E;}
+    static char const* const* c() {return C;}
+};
+
+#endif // mc_enum_metadata_hpp
+


Property changes on: lmi/trunk/mc_enum_metadata.hpp
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:keywords
   + Id

Modified: lmi/trunk/mc_enum_test.cpp
===================================================================
--- lmi/trunk/mc_enum_test.cpp  2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_test.cpp  2010-02-24 19:04:23 UTC (rev 4776)
@@ -27,7 +27,7 @@
 #endif // __BORLANDC__
 
 #include "mc_enum.hpp"
-#include "mc_enum.tpp" // Template class implementation.
+#include "mc_enum.tpp"
 #include "mc_enum_test_aux.hpp"
 
 #include "test_tools.hpp"
@@ -41,8 +41,10 @@
 enum enum_island {i_Easter = 37, i_Pago_Pago = -17, i_Ni_ihau = 13};
 extern enum_island const island_enums[] = {i_Easter, i_Pago_Pago, i_Ni_ihau};
 extern char const*const island_strings[] = {"Easter", "Pago Pago", "Ni_ihau"};
-template class mc_enum<enum_island, 3, island_enums, island_strings>;
-typedef mc_enum<enum_island, 3, island_enums, island_strings> e_island;
+template<> struct mc_enum_key<enum_island>
+  :public mc_enum_data<enum_island, 3, island_enums, island_strings> {};
+template class mc_enum<enum_island>;
+typedef mc_enum<enum_island> e_island;
 
 // Enumerative type 'e_holiday' is explicitly instantiated in a
 // different translation unit.

Modified: lmi/trunk/mc_enum_test_aux.cpp
===================================================================
--- lmi/trunk/mc_enum_test_aux.cpp      2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_test_aux.cpp      2010-02-24 19:04:23 UTC (rev 4776)
@@ -26,7 +26,7 @@
 #   pragma hdrstop
 #endif // __BORLANDC__
 
-#include "mc_enum.tpp"                // Template class implementation.
+#include "mc_enum.hpp"
 #include "mc_enum_test_aux_enums.hpp" // Plain enums.
 
 // Normally, one would prefer to instantiate all mc_enum templates
@@ -44,5 +44,19 @@
     ,"Easter"
     ,"Pentecost"
     };
-template class mc_enum<enum_holiday, 3, holiday_enums, holiday_strings>;
+template class mc_enum<enum_holiday>;
 
+// Explicit instantiation of class mc_enum above does not require a
+// definition of mc_enum_key<T>, which does not appear in the class
+// definition. However, because mc_enum_key<T> is used in the bodies
+// of member functions, it must be defined in this TU--before the
+// point of explicit instantiation of the member functions, but not
+// necessarily of the class [14.5.1.1/1]. The reason for including
+// its definition below rather than above is to force array bounds to
+// be 'calculated' [8.3.4/3], so that errors are detected at compile
+// time: this is the motivation for keeping class template mc_enum
+// and its metadata physically separate.
+
+#include "mc_enum.tpp"
+#include "mc_enum_test_aux.hpp"
+

Modified: lmi/trunk/mc_enum_test_aux.hpp
===================================================================
--- lmi/trunk/mc_enum_test_aux.hpp      2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_test_aux.hpp      2010-02-24 19:04:23 UTC (rev 4776)
@@ -27,11 +27,14 @@
 #include "config.hpp"
 
 #include "mc_enum_fwd.hpp"
+#include "mc_enum_metadata.hpp"
 #include "mc_enum_test_aux_enums.hpp"
 
 extern enum_holiday const holiday_enums[3];
 extern char const*const holiday_strings[3];
-typedef mc_enum<enum_holiday, 3, holiday_enums, holiday_strings> e_holiday;
+template<> struct mc_enum_key<enum_holiday>
+  :public mc_enum_data<enum_holiday, 3, holiday_enums, holiday_strings> {};
+typedef mc_enum<enum_holiday> e_holiday;
 
 #endif // mc_enum_test_aux_hpp
 

Modified: lmi/trunk/mc_enum_types.cpp
===================================================================
--- lmi/trunk/mc_enum_types.cpp 2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_types.cpp 2010-02-24 19:04:23 UTC (rev 4776)
@@ -26,7 +26,7 @@
 #   pragma hdrstop
 #endif // __BORLANDC__
 
-#include "mc_enum.tpp"            // Template class implementation.
+#include "mc_enum.hpp"
 #include "mc_enum_type_enums.hpp" // Plain enums.
 
 // Here write illustrative examples and anything that doesn't follow
@@ -53,7 +53,7 @@
     ,"B"
     ,"C"
     };
-template class mc_enum<enum_option, 3, option_enums, option_strings>;
+template class mc_enum<enum_option>;
 
 extern mcenum_emission const emission_enums[] =
     {mce_emit_nothing
@@ -81,53 +81,67 @@
     ,"emit_text_stream"
     ,"emit_custom_0"
     };
-template class mc_enum<mcenum_emission, 11, emission_enums, emission_strings>;
+template class mc_enum<mcenum_emission>;
 
 #include "mc_enum_types.xpp"
 
-#define MC_DEFINE(TYPE,NUMBER) \
+#define MC_DEFINE(TYPE) \
 extern mcenum_##TYPE const TYPE##_enums[] = TYPE##_VALUES \
 extern char const*const TYPE##_strings[] = TYPE##_NAMES \
-template class mc_enum<mcenum_##TYPE, NUMBER, TYPE##_enums, TYPE##_strings>;
+template class mc_enum<mcenum_##TYPE>;
 
-MC_DEFINE(yes_or_no,2)
-MC_DEFINE(gender,3)
-MC_DEFINE(smoking,3)
-MC_DEFINE(class,4)
-MC_DEFINE(dbopt,3)
-MC_DEFINE(dbopt_7702,2)
-MC_DEFINE(mode,4)
-MC_DEFINE(gen_basis,3)
-MC_DEFINE(sep_basis,3)
-MC_DEFINE(rate_period,2)
-MC_DEFINE(run_basis,7)
-MC_DEFINE(ledger_type,8)
-MC_DEFINE(uw_basis,5)
-MC_DEFINE(table_rating,11)
-MC_DEFINE(solve_type,6)
-MC_DEFINE(solve_target,4)
-MC_DEFINE(pmt_strategy,8)
-MC_DEFINE(sa_strategy,8)
-MC_DEFINE(gen_acct_rate_type,2)
-MC_DEFINE(sep_acct_rate_type,2)
-MC_DEFINE(loan_rate_type,2)
-MC_DEFINE(fund_input_method,3)
-MC_DEFINE(run_order,2)
-MC_DEFINE(survival_limit,4)
-MC_DEFINE(term_adj_method,3)
-MC_DEFINE(state,53)
-MC_DEFINE(country,239)
-MC_DEFINE(defn_life_ins,3)
-MC_DEFINE(mec_avoid_method,2)
-MC_DEFINE(defn_material_change,5)
-MC_DEFINE(spread_method,2)
-MC_DEFINE(coi_rate_method,2)
-MC_DEFINE(anticipated_deduction,4)
-MC_DEFINE(part_mort_table,1)
-MC_DEFINE(premium_table,1)
-MC_DEFINE(from_point,4)
-MC_DEFINE(to_point,4)
-MC_DEFINE(report_column,56)
+MC_DEFINE(yes_or_no)
+MC_DEFINE(gender)
+MC_DEFINE(smoking)
+MC_DEFINE(class)
+MC_DEFINE(dbopt)
+MC_DEFINE(dbopt_7702)
+MC_DEFINE(mode)
+MC_DEFINE(gen_basis)
+MC_DEFINE(sep_basis)
+MC_DEFINE(rate_period)
+MC_DEFINE(run_basis)
+MC_DEFINE(ledger_type)
+MC_DEFINE(uw_basis)
+MC_DEFINE(table_rating)
+MC_DEFINE(solve_type)
+MC_DEFINE(solve_target)
+MC_DEFINE(pmt_strategy)
+MC_DEFINE(sa_strategy)
+MC_DEFINE(gen_acct_rate_type)
+MC_DEFINE(sep_acct_rate_type)
+MC_DEFINE(loan_rate_type)
+MC_DEFINE(fund_input_method)
+MC_DEFINE(run_order)
+MC_DEFINE(survival_limit)
+MC_DEFINE(term_adj_method)
+MC_DEFINE(state)
+MC_DEFINE(country)
+MC_DEFINE(defn_life_ins)
+MC_DEFINE(mec_avoid_method)
+MC_DEFINE(defn_material_change)
+MC_DEFINE(spread_method)
+MC_DEFINE(coi_rate_method)
+MC_DEFINE(anticipated_deduction)
+MC_DEFINE(part_mort_table)
+MC_DEFINE(premium_table)
+MC_DEFINE(from_point)
+MC_DEFINE(to_point)
+MC_DEFINE(report_column)
 
 #undef MC_DEFINE
 
+// Explicit instantiation of class mc_enum above does not require a
+// definition of mc_enum_key<T>, which does not appear in the class
+// definition. However, because mc_enum_key<T> is used in the bodies
+// of member functions, it must be defined in this TU--before the
+// point of explicit instantiation of the member functions, but not
+// necessarily of the class [14.5.1.1/1]. The reason for including
+// its definition below rather than above is to force array bounds to
+// be 'calculated' [8.3.4/3], so that errors are detected at compile
+// time: this is the motivation for keeping class template mc_enum
+// and its metadata physically separate.
+
+#include "mc_enum.tpp"
+#include "mc_enum_types.hpp"
+

Modified: lmi/trunk/mc_enum_types.hpp
===================================================================
--- lmi/trunk/mc_enum_types.hpp 2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_types.hpp 2010-02-24 19:04:23 UTC (rev 4776)
@@ -26,7 +26,8 @@
 
 #include "config.hpp"
 
-#include "mc_enum_fwd.hpp"        // Template class forward declaration.
+#include "mc_enum_fwd.hpp"
+#include "mc_enum_metadata.hpp"
 #include "mc_enum_type_enums.hpp" // Plain enumerators.
 
 // Here write illustrative examples and anything that doesn't follow
@@ -34,18 +35,22 @@
 
 extern enum_option const option_enums[3];
 extern char const*const option_strings[3];
-typedef mc_enum<enum_option, 3, option_enums, option_strings> e_option;
+template<> struct mc_enum_key<enum_option>
+  :public mc_enum_data<enum_option, 3, option_enums, option_strings> {};
+typedef mc_enum<enum_option> e_option;
 
 extern mcenum_emission const emission_enums[11];
 extern char const*const emission_strings[11];
-typedef mc_enum<mcenum_emission, 11, emission_enums, emission_strings> 
e_emission;
+template<> struct mc_enum_key<mcenum_emission>
+  :public mc_enum_data<mcenum_emission, 11, emission_enums, emission_strings> 
{};
+typedef mc_enum<mcenum_emission> e_emission;
 
-#include "mc_enum_types.xpp"
-
 #define MC_DECLARE(TYPE,NUMBER) \
 extern mcenum_##TYPE const TYPE##_enums[NUMBER]; \
 extern char const*const TYPE##_strings[NUMBER]; \
-typedef mc_enum<mcenum_##TYPE, NUMBER, TYPE##_enums, TYPE##_strings> 
mce_##TYPE;
+template<> struct mc_enum_key<mcenum_##TYPE> \
+  :public mc_enum_data<mcenum_##TYPE, NUMBER, TYPE##_enums, TYPE##_strings> 
{}; \
+typedef mc_enum<mcenum_##TYPE> mce_##TYPE;
 
 MC_DECLARE(yes_or_no,2)
 MC_DECLARE(gender,3)

Modified: lmi/trunk/mc_enum_types_aux.cpp
===================================================================
--- lmi/trunk/mc_enum_types_aux.cpp     2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/mc_enum_types_aux.cpp     2010-02-24 19:04:23 UTC (rev 4776)
@@ -34,10 +34,15 @@
 
 #include <boost/static_assert.hpp>
 
-BOOST_STATIC_ASSERT(mc_n_gen_bases    == 
static_cast<std::size_t>(mce_gen_basis  ::Cardinality));
-BOOST_STATIC_ASSERT(mc_n_sep_bases    == 
static_cast<std::size_t>(mce_sep_basis  ::Cardinality));
-BOOST_STATIC_ASSERT(mc_n_rate_periods == 
static_cast<std::size_t>(mce_rate_period::Cardinality));
+// The 'mc_n_' values could be initialized in the header with the
+// values they're tested against here, but that would complicate
+// the physical design. It's better to exclude heavyweight mc_enum
+// metadata from any header in which it's not indispensable.
 
+BOOST_STATIC_ASSERT(mc_n_gen_bases    == mc_enum_key<mcenum_gen_basis  >::n_);
+BOOST_STATIC_ASSERT(mc_n_sep_bases    == mc_enum_key<mcenum_sep_basis  >::n_);
+BOOST_STATIC_ASSERT(mc_n_rate_periods == mc_enum_key<mcenum_rate_period>::n_);
+
 std::vector<std::string> const& LMI_SO all_strings_gender   () {return 
mce_gender  ::all_strings();}
 std::vector<std::string> const& LMI_SO all_strings_class    () {return 
mce_class   ::all_strings();}
 std::vector<std::string> const& LMI_SO all_strings_smoking  () {return 
mce_smoking ::all_strings();}

Modified: lmi/trunk/yare_input.cpp
===================================================================
--- lmi/trunk/yare_input.cpp    2010-02-24 03:02:27 UTC (rev 4775)
+++ lmi/trunk/yare_input.cpp    2010-02-24 19:04:23 UTC (rev 4776)
@@ -35,13 +35,13 @@
 
 namespace
 {
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+template<typename T>
 std::vector<T> convert_vector_type
-    (std::vector<mc_enum<T,n,e,c> > const& ve
+    (std::vector<mc_enum<T> > const& ve
     )
 {
     std::vector<T> z;
-    typename std::vector<mc_enum<T,n,e,c> >::const_iterator ve_i;
+    typename std::vector<mc_enum<T> >::const_iterator ve_i;
     for(ve_i = ve.begin(); ve_i != ve.end(); ++ve_i)
         {
         z.push_back(ve_i->value());





reply via email to

[Prev in Thread] Current Thread [Next in Thread]