[Top][All Lists]
[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());
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [4776] Refactor (VS),
Greg Chicares <=