lmi
[Top][All Lists]
Advanced

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

[lmi] a bad MSVC problem with mc_enum


From: Vadim Zeitlin
Subject: [lmi] a bad MSVC problem with mc_enum
Date: Mon, 23 Jun 2008 07:26:10 +0200

 Hello,

 I've found what seems an amazingly bad bug in MSVC compiler: it happily
compiles the current code in mc_enum.[cht]pp but it doesn't seem to be able
to handle references to arrays correctly. To be precise, the code crashes
at run-time (both in test_mc_enum unit test and LMI itself) because all
functions in mc_enum.tpp use wrong value of the template "e" and "c"
arguments: instead of using the arrays themselves, they use the value of
the first array element instead. This is pretty clear when looking at the
disassembly (there is an extra dereference which has nothing to do there)
and unfortunately seems unavoidable.

 The only workaround I found so far is to use pointers, and not references,
to arrays -- then everything works correctly. But this is, of course,
pretty ugly and I'm not sure if the mechanism described in the comment
before mc_enum declaration still works in this case. And it needs using
extra "address of" operators when defining mc_enum specializations. But,
again, I just don't seem to be able to find any other way to make the
compiler generate the correct code after spending close to 2 hours on it.

 As usual, if anybody has any ideas about how to make this work otherwise,
I'd love to hear about them. In the meanwhile, here is the patch I'm using
right now, just for the reference:

--- mc_enum.hpp 2008-06-22 22:38:54 +0000
+++ mc_enum.hpp 2008-06-23 05:07:20 +0000
@@ -137,7 +137,7 @@
 /// macro. This built-in approach is preferred because it avoids using
 /// the preprocessor and its compile-time checking is automatic.
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+template<typename T, std::size_t n, T const (*e)[n], char const*const (*c)[n]>
 class mc_enum
     :public mc_enum_base
     ,private boost::equality_comparable<mc_enum<T,n,e,c>, mc_enum<T,n,e,c> >

--- mc_enum.tpp 2008-06-22 22:38:54 +0000
+++ mc_enum.tpp 2008-06-23 05:10:17 +0000
@@ -33,57 +33,57 @@
 // 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]>
+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])
+    ,value_((*e)[0])
 {}
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[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)
     ,value_(t)
 {}
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[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(std::string const& s)
     :mc_enum_base(n)
-    ,value_(e[ordinal(s)])
+    ,value_((*e)[ordinal(s)])
 {}
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[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,n,e,c>::operator=(T t)
 {
     value_ = t;
     return *this;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[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,n,e,c>::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]>
+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
 {
     return z.value_ == value_;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
     return t == value_;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
     return s == str();
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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)
 {
     std::locale old_locale = is.imbue(blank_is_not_whitespace_locale());
@@ -94,19 +94,19 @@
     return is;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
     return os << str();
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
     return n;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[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()
 {
     if(is_allowed(ordinal()))
@@ -117,15 +117,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]>
+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
 {
 // TODO ?? Shouldn't this be ptrdiff_t?
-    std::size_t i = std::find(e, e + n, value_) - e;
+    std::size_t i = std::find(*e, *e + n, value_) - *e;
     if(i == n)
         {
         fatal_error()
@@ -140,23 +140,23 @@
     return i;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
-    return c[j];
+    return (*c)[j];
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
     return value_;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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)
 {
 // TODO ?? Shouldn't this be ptrdiff_t?
-    std::size_t v = std::find(c, c + n, s) - c;
+    std::size_t v = std::find(*c, *c + n, s) - *c;
     if(v == n)
         {
         fatal_error()
@@ -171,9 +171,9 @@
     return v;
 }
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+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
 {
-    return c[ordinal()];
+    return (*c)[ordinal()];
 }
 

--- mc_enum_fwd.hpp     2008-01-01 18:30:08 +0000
+++ mc_enum_fwd.hpp     2008-06-23 05:07:59 +0000
@@ -28,7 +28,7 @@
 
 #include <cstddef> // std::size_t
 
-template<typename T, std::size_t n, T const (&e)[n], char const*const (&c)[n]>
+template<typename T, std::size_t n, T const (*e)[n], char const*const (*c)[n]>
 class mc_enum;
 
 #endif // mc_enum_fwd_hpp

--- mc_enum_test.cpp    2008-06-23 01:12:28 +0000
+++ mc_enum_test.cpp    2008-06-23 05:10:17 +0000
@@ -38,8 +38,8 @@
 enum enum_island {i_Easter = 37, i_Pago_Pago = -17};
 extern enum_island const island_enums[] = {i_Easter, i_Pago_Pago};
 extern char const*const island_strings[] = {"Easter", "Pago Pago"};
-template class mc_enum<enum_island, 2, island_enums, island_strings>;
-typedef mc_enum<enum_island, 2, island_enums, island_strings> e_island;
+template class mc_enum<enum_island, 2, &island_enums, &island_strings>;
+typedef mc_enum<enum_island, 2, &island_enums, &island_strings> e_island;
 
 // Enumerative type 'e_holiday' is explicitly instantiated in a
 // different translation unit.

--- mc_enum_test_aux.cpp        2008-01-01 18:30:08 +0000
+++ mc_enum_test_aux.cpp        2008-06-23 05:08:01 +0000
@@ -44,5 +44,5 @@
     ,"Easter"
     ,"Pentecost"
     };
-template class mc_enum<enum_holiday, 3, holiday_enums, holiday_strings>;
+template class mc_enum<enum_holiday, 3, &holiday_enums, &holiday_strings>;
 

--- mc_enum_test_aux.hpp        2008-01-01 18:30:08 +0000
+++ mc_enum_test_aux.hpp        2008-06-23 05:10:17 +0000
@@ -31,7 +31,7 @@
 
 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;
+typedef mc_enum<enum_holiday, 3, &holiday_enums, &holiday_strings> e_holiday;
 
 #endif // mc_enum_test_aux_hpp
 

--- mc_enum_types.cpp   2008-01-01 18:30:08 +0000
+++ mc_enum_types.cpp   2008-06-23 05:13:01 +0000
@@ -53,7 +53,7 @@
     ,"B"
     ,"C"
     };
-template class mc_enum<enum_option, 3, option_enums, option_strings>;
+template class mc_enum<enum_option, 3, &option_enums, &option_strings>;
 
 extern mcenum_emission const emission_enums[] =
     {mce_emit_nothing
@@ -79,14 +79,14 @@
     ,"emit_text_stream"
     ,"emit_custom_0"
     };
-template class mc_enum<mcenum_emission, 10, emission_enums, emission_strings>;
+template class mc_enum<mcenum_emission, 10, &emission_enums, 
&emission_strings>;
 
 #include "mc_enum_types.xpp"
 
 #define MC_DEFINE(TYPE,NUMBER) \
 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, NUMBER, &TYPE##_enums, &TYPE##_strings>;
 
 MC_DEFINE(yes_or_no,2)
 MC_DEFINE(gender,3)

--- mc_enum_types.hpp   2008-01-01 18:30:08 +0000
+++ mc_enum_types.hpp   2008-06-23 05:12:19 +0000
@@ -34,18 +34,18 @@
 
 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;
+typedef mc_enum<enum_option, 3, &option_enums, &option_strings> e_option;
 
 extern mcenum_emission const emission_enums[10];
 extern char const*const emission_strings[10];
-typedef mc_enum<mcenum_emission, 10, emission_enums, emission_strings> 
e_emission;
+typedef mc_enum<mcenum_emission, 10, &emission_enums, &emission_strings> 
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;
+typedef mc_enum<mcenum_##TYPE, NUMBER, &TYPE##_enums, &TYPE##_strings> 
mce_##TYPE;
 
 MC_DECLARE(yes_or_no,2)
 MC_DECLARE(gender,3)


 Regards,
VZ





reply via email to

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