1
0
Эх сурвалжийг харах

Merge topic 'cm-optional-comparison'

7e1304c6e6 cm::optional: Add comparison operators
c854e9eba5 Refactor: Add ASSERT_TRUE() macro to testOptional.cxx

Acked-by: Kitware Robot <[email protected]>
Merge-request: !5195
Kyle Edwards 5 жил өмнө
parent
commit
1d74a64f38

+ 197 - 118
Tests/CMakeLib/testOptional.cxx

@@ -29,6 +29,13 @@ public:
     CONST_RVALUE_REFERENCE,
 
     SWAP,
+
+    COMPARE_EE_EQ,
+    COMPARE_EE_NE,
+    COMPARE_EE_LT,
+    COMPARE_EE_LE,
+    COMPARE_EE_GT,
+    COMPARE_EE_GE,
   };
 
   EventType Type;
@@ -75,6 +82,14 @@ public:
   int Value = 0;
 };
 
+#define ASSERT_TRUE(x)                                                        \
+  do {                                                                        \
+    if (!(x)) {                                                               \
+      std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
+      return false;                                                           \
+    }                                                                         \
+  } while (false)
+
 // Certain builds of GCC generate false -Wmaybe-uninitialized warnings when
 // doing a release build with the system version of std::optional. These
 // warnings do not manifest when using our own cm::optional implementation.
@@ -153,6 +168,42 @@ EventLogger& EventLogger::operator=(int value)
   return *this;
 }
 
+bool operator==(const EventLogger& lhs, const EventLogger& rhs)
+{
+  events.push_back({ Event::COMPARE_EE_EQ, &lhs, &rhs, lhs.Value });
+  return lhs.Value == rhs.Value;
+}
+
+bool operator!=(const EventLogger& lhs, const EventLogger& rhs)
+{
+  events.push_back({ Event::COMPARE_EE_NE, &lhs, &rhs, lhs.Value });
+  return lhs.Value != rhs.Value;
+}
+
+bool operator<(const EventLogger& lhs, const EventLogger& rhs)
+{
+  events.push_back({ Event::COMPARE_EE_LT, &lhs, &rhs, lhs.Value });
+  return lhs.Value < rhs.Value;
+}
+
+bool operator<=(const EventLogger& lhs, const EventLogger& rhs)
+{
+  events.push_back({ Event::COMPARE_EE_LE, &lhs, &rhs, lhs.Value });
+  return lhs.Value <= rhs.Value;
+}
+
+bool operator>(const EventLogger& lhs, const EventLogger& rhs)
+{
+  events.push_back({ Event::COMPARE_EE_GT, &lhs, &rhs, lhs.Value });
+  return lhs.Value > rhs.Value;
+}
+
+bool operator>=(const EventLogger& lhs, const EventLogger& rhs)
+{
+  events.push_back({ Event::COMPARE_EE_GE, &lhs, &rhs, lhs.Value });
+  return lhs.Value >= rhs.Value;
+}
+
 void EventLogger::Reference() &
 {
   events.push_back({ Event::REFERENCE, this, nullptr, this->Value });
@@ -368,42 +419,23 @@ static bool testDereference(std::vector<Event>& expected)
 
 static bool testHasValue(std::vector<Event>& expected)
 {
-  bool retval = true;
-
   const cm::optional<EventLogger> o1{ 4 };
   const cm::optional<EventLogger> o2{};
 
-  if (!o1.has_value()) {
-    std::cout << "o1 should have a value" << std::endl;
-    retval = false;
-  }
-
-  if (!o1) {
-    std::cout << "(bool)o1 should be true" << std::endl;
-    retval = false;
-  }
-
-  if (o2.has_value()) {
-    std::cout << "o2 should not have a value" << std::endl;
-    retval = false;
-  }
-
-  if (o2) {
-    std::cout << "(bool)o2 should be false" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(o1.has_value());
+  ASSERT_TRUE(o1);
+  ASSERT_TRUE(!o2.has_value());
+  ASSERT_TRUE(!o2);
 
   expected = {
     { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
     { Event::DESTRUCT, &*o1, nullptr, 4 },
   };
-  return retval;
+  return true;
 }
 
 static bool testValue(std::vector<Event>& expected)
 {
-  bool retval = true;
-
   cm::optional<EventLogger> o1{ 4 };
   const cm::optional<EventLogger> o2{ 5 };
   cm::optional<EventLogger> o3{};
@@ -418,10 +450,7 @@ static bool testValue(std::vector<Event>& expected)
   } catch (cm::bad_optional_access&) {
     thrown = true;
   }
-  if (!thrown) {
-    std::cout << "o3.value() did not throw" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(thrown);
 
   thrown = false;
   try {
@@ -429,10 +458,7 @@ static bool testValue(std::vector<Event>& expected)
   } catch (cm::bad_optional_access&) {
     thrown = true;
   }
-  if (!thrown) {
-    std::cout << "o4.value() did not throw" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(thrown);
 
   expected = {
     { Event::VALUE_CONSTRUCT, &*o1, nullptr, 4 },
@@ -442,13 +468,11 @@ static bool testValue(std::vector<Event>& expected)
     { Event::DESTRUCT, &*o2, nullptr, 5 },
     { Event::DESTRUCT, &*o1, nullptr, 4 },
   };
-  return retval;
+  return true;
 }
 
 static bool testValueOr()
 {
-  bool retval = true;
-
   const cm::optional<EventLogger> o1{ 4 };
   cm::optional<EventLogger> o2{ 5 };
   const cm::optional<EventLogger> o3{};
@@ -460,33 +484,133 @@ static bool testValueOr()
   EventLogger e4{ 9 };
 
   EventLogger r1 = o1.value_or(e1);
-  if (r1.Value != 4) {
-    std::cout << "r1.Value should be 4" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(r1.Value == 4);
   EventLogger r2 = std::move(o2).value_or(e2);
-  if (r2.Value != 5) {
-    std::cout << "r2.Value should be 5" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(r2.Value == 5);
   EventLogger r3 = o3.value_or(e3);
-  if (r3.Value != 8) {
-    std::cout << "r3.Value should be 8" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(r3.Value == 8);
   EventLogger r4 = std::move(o4).value_or(e4);
-  if (r4.Value != 9) {
-    std::cout << "r4.Value should be 9" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(r4.Value == 9);
 
-  return retval;
+  return true;
 }
 
-static bool testSwap(std::vector<Event>& expected)
+static bool testComparison(std::vector<Event>& expected)
 {
-  bool retval = true;
+  const cm::optional<EventLogger> o1{ 1 };
+  const cm::optional<EventLogger> o2{ 2 };
+  const cm::optional<EventLogger> o3{ 2 };
+  const cm::optional<EventLogger> o4{};
+  const cm::optional<EventLogger> o5{};
+  const EventLogger e1{ 2 };
+
+  ASSERT_TRUE(!(o1 == o2) && o1 != o2);
+  ASSERT_TRUE(o1 < o2 && !(o1 >= o2));
+  ASSERT_TRUE(!(o1 > o2) && o1 <= o2);
+
+  ASSERT_TRUE(o2 == o3 && !(o2 != o3));
+  ASSERT_TRUE(!(o2 < o3) && o2 >= o3);
+  ASSERT_TRUE(!(o2 > o3) && o2 <= o3);
+
+  ASSERT_TRUE(!(o3 == o4) && o3 != o4);
+  ASSERT_TRUE(!(o3 < o4) && o3 >= o4);
+  ASSERT_TRUE(o3 > o4 && !(o3 <= o4));
+
+  ASSERT_TRUE(o4 == o5 && !(o4 != o5));
+  ASSERT_TRUE(!(o4 < o5) && o4 >= o5);
+  ASSERT_TRUE(!(o4 > o5) && o4 <= o5);
+
+  ASSERT_TRUE(!(o1 == cm::nullopt) && o1 != cm::nullopt);
+  ASSERT_TRUE(!(o1 < cm::nullopt) && o1 >= cm::nullopt);
+  ASSERT_TRUE(o1 > cm::nullopt && !(o1 <= cm::nullopt));
+
+  ASSERT_TRUE(!(cm::nullopt == o1) && cm::nullopt != o1);
+  ASSERT_TRUE(cm::nullopt < o1 && !(cm::nullopt >= o1));
+  ASSERT_TRUE(!(cm::nullopt > o1) && cm::nullopt <= o1);
+
+  ASSERT_TRUE(o4 == cm::nullopt && !(o4 != cm::nullopt));
+  ASSERT_TRUE(!(o4 < cm::nullopt) && o4 >= cm::nullopt);
+  ASSERT_TRUE(!(o4 > cm::nullopt) && o4 <= cm::nullopt);
+
+  ASSERT_TRUE(cm::nullopt == o4 && !(cm::nullopt != o4));
+  ASSERT_TRUE(!(cm::nullopt < o4) && cm::nullopt >= o4);
+  ASSERT_TRUE(!(cm::nullopt > o4) && cm::nullopt <= o4);
+
+  ASSERT_TRUE(!(o1 == e1) && o1 != e1);
+  ASSERT_TRUE(o1 < e1 && !(o1 >= e1));
+  ASSERT_TRUE(!(o1 > e1) && o1 <= e1);
+
+  ASSERT_TRUE(o2 == e1 && !(o2 != e1));
+  ASSERT_TRUE(!(o2 < e1) && o2 >= e1);
+  ASSERT_TRUE(!(o2 > e1) && o2 <= e1);
 
+  ASSERT_TRUE(!(o4 == e1) && o4 != e1);
+  ASSERT_TRUE(o4 < e1 && !(o4 >= e1));
+  ASSERT_TRUE(!(o4 > e1) && o4 <= e1);
+
+  ASSERT_TRUE(!(e1 == o1) && e1 != o1);
+  ASSERT_TRUE(!(e1 < o1) && e1 >= o1);
+  ASSERT_TRUE(e1 > o1 && !(e1 <= o1));
+
+  ASSERT_TRUE(e1 == o2 && !(e1 != o2));
+  ASSERT_TRUE(!(e1 < o2) && e1 >= o2);
+  ASSERT_TRUE(!(e1 > o2) && e1 <= o2);
+
+  ASSERT_TRUE(!(e1 == o4) && e1 != o4);
+  ASSERT_TRUE(!(e1 < o4) && e1 >= o4);
+  ASSERT_TRUE(e1 > o4 && !(e1 <= o4));
+
+  expected = {
+    { Event::VALUE_CONSTRUCT, &*o1, nullptr, 1 },
+    { Event::VALUE_CONSTRUCT, &*o2, nullptr, 2 },
+    { Event::VALUE_CONSTRUCT, &*o3, nullptr, 2 },
+    { Event::VALUE_CONSTRUCT, &e1, nullptr, 2 },
+    { Event::COMPARE_EE_EQ, &*o1, &*o2, 1 },
+    { Event::COMPARE_EE_NE, &*o1, &*o2, 1 },
+    { Event::COMPARE_EE_LT, &*o1, &*o2, 1 },
+    { Event::COMPARE_EE_GE, &*o1, &*o2, 1 },
+    { Event::COMPARE_EE_GT, &*o1, &*o2, 1 },
+    { Event::COMPARE_EE_LE, &*o1, &*o2, 1 },
+    { Event::COMPARE_EE_EQ, &*o2, &*o3, 2 },
+    { Event::COMPARE_EE_NE, &*o2, &*o3, 2 },
+    { Event::COMPARE_EE_LT, &*o2, &*o3, 2 },
+    { Event::COMPARE_EE_GE, &*o2, &*o3, 2 },
+    { Event::COMPARE_EE_GT, &*o2, &*o3, 2 },
+    { Event::COMPARE_EE_LE, &*o2, &*o3, 2 },
+    { Event::COMPARE_EE_EQ, &*o1, &e1, 1 },
+    { Event::COMPARE_EE_NE, &*o1, &e1, 1 },
+    { Event::COMPARE_EE_LT, &*o1, &e1, 1 },
+    { Event::COMPARE_EE_GE, &*o1, &e1, 1 },
+    { Event::COMPARE_EE_GT, &*o1, &e1, 1 },
+    { Event::COMPARE_EE_LE, &*o1, &e1, 1 },
+    { Event::COMPARE_EE_EQ, &*o2, &e1, 2 },
+    { Event::COMPARE_EE_NE, &*o2, &e1, 2 },
+    { Event::COMPARE_EE_LT, &*o2, &e1, 2 },
+    { Event::COMPARE_EE_GE, &*o2, &e1, 2 },
+    { Event::COMPARE_EE_GT, &*o2, &e1, 2 },
+    { Event::COMPARE_EE_LE, &*o2, &e1, 2 },
+    { Event::COMPARE_EE_EQ, &e1, &*o1, 2 },
+    { Event::COMPARE_EE_NE, &e1, &*o1, 2 },
+    { Event::COMPARE_EE_LT, &e1, &*o1, 2 },
+    { Event::COMPARE_EE_GE, &e1, &*o1, 2 },
+    { Event::COMPARE_EE_GT, &e1, &*o1, 2 },
+    { Event::COMPARE_EE_LE, &e1, &*o1, 2 },
+    { Event::COMPARE_EE_EQ, &e1, &*o2, 2 },
+    { Event::COMPARE_EE_NE, &e1, &*o2, 2 },
+    { Event::COMPARE_EE_LT, &e1, &*o2, 2 },
+    { Event::COMPARE_EE_GE, &e1, &*o2, 2 },
+    { Event::COMPARE_EE_GT, &e1, &*o2, 2 },
+    { Event::COMPARE_EE_LE, &e1, &*o2, 2 },
+    { Event::DESTRUCT, &e1, nullptr, 2 },
+    { Event::DESTRUCT, &*o3, nullptr, 2 },
+    { Event::DESTRUCT, &*o2, nullptr, 2 },
+    { Event::DESTRUCT, &*o1, nullptr, 1 },
+  };
+  return true;
+}
+
+static bool testSwap(std::vector<Event>& expected)
+{
   cm::optional<EventLogger> o1{ 4 };
   auto const* v1 = &*o1;
   cm::optional<EventLogger> o2{};
@@ -494,66 +618,30 @@ static bool testSwap(std::vector<Event>& expected)
   o1.swap(o2);
   auto const* v2 = &*o2;
 
-  if (o1.has_value()) {
-    std::cout << "o1 should not have value" << std::endl;
-    retval = false;
-  }
-  if (!o2.has_value()) {
-    std::cout << "o2 should have value" << std::endl;
-    retval = false;
-  }
-  if (o2.value().Value != 4) {
-    std::cout << "value of o2 should be 4" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(!o1.has_value());
+  ASSERT_TRUE(o2.has_value());
+  ASSERT_TRUE(o2.value().Value == 4);
 
   o1.swap(o2);
 
-  if (!o1.has_value()) {
-    std::cout << "o1 should have value" << std::endl;
-    retval = false;
-  }
-  if (o1.value().Value != 4) {
-    std::cout << "value of o1 should be 4" << std::endl;
-    retval = false;
-  }
-  if (o2.has_value()) {
-    std::cout << "o2 should not have value" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(o1.has_value());
+  ASSERT_TRUE(o1.value().Value == 4);
+  ASSERT_TRUE(!o2.has_value());
 
   o2.emplace(5);
   o1.swap(o2);
 
-  if (!o1.has_value()) {
-    std::cout << "o1 should have value" << std::endl;
-    retval = false;
-  }
-  if (o1.value().Value != 5) {
-    std::cout << "value of o1 should be 5" << std::endl;
-    retval = false;
-  }
-  if (!o2.has_value()) {
-    std::cout << "o2 should not have value" << std::endl;
-    retval = false;
-  }
-  if (o2.value().Value != 4) {
-    std::cout << "value of o2 should be 4" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(o1.has_value());
+  ASSERT_TRUE(o1.value().Value == 5);
+  ASSERT_TRUE(o2.has_value());
+  ASSERT_TRUE(o2.value().Value == 4);
 
   o1.reset();
   o2.reset();
   o1.swap(o2);
 
-  if (o1.has_value()) {
-    std::cout << "o1 should not have value" << std::endl;
-    retval = false;
-  }
-  if (o2.has_value()) {
-    std::cout << "o2 should not have value" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(!o1.has_value());
+  ASSERT_TRUE(!o2.has_value());
 
   expected = {
     { Event::VALUE_CONSTRUCT, v1, nullptr, 4 },
@@ -566,22 +654,17 @@ static bool testSwap(std::vector<Event>& expected)
     { Event::DESTRUCT, v1, nullptr, 5 },
     { Event::DESTRUCT, v2, nullptr, 4 },
   };
-  return retval;
+  return true;
 }
 
 static bool testReset(std::vector<Event>& expected)
 {
-  bool retval = true;
-
   cm::optional<EventLogger> o{ 4 };
   auto const* v = &*o;
 
   o.reset();
 
-  if (o.has_value()) {
-    std::cout << "o should not have value" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(!o.has_value());
 
   o.reset();
 
@@ -589,7 +672,7 @@ static bool testReset(std::vector<Event>& expected)
     { Event::VALUE_CONSTRUCT, v, nullptr, 4 },
     { Event::DESTRUCT, v, nullptr, 4 },
   };
-  return retval;
+  return true;
 }
 
 static bool testEmplace(std::vector<Event>& expected)
@@ -630,8 +713,6 @@ static bool testMakeOptional(std::vector<Event>& expected)
 
 static bool testMemoryRange(std::vector<Event>& expected)
 {
-  bool retval = true;
-
   cm::optional<EventLogger> o{ 4 };
 
   auto* ostart = &o;
@@ -639,17 +720,14 @@ static bool testMemoryRange(std::vector<Event>& expected)
   auto* estart = &o.value();
   auto* eend = estart + 1;
 
-  if (static_cast<void*>(estart) < static_cast<void*>(ostart) ||
-      static_cast<void*>(eend) > static_cast<void*>(oend)) {
-    std::cout << "value is not within memory range of optional" << std::endl;
-    retval = false;
-  }
+  ASSERT_TRUE(static_cast<void*>(estart) >= static_cast<void*>(ostart) &&
+              static_cast<void*>(eend) <= static_cast<void*>(oend));
 
   expected = {
     { Event::VALUE_CONSTRUCT, &*o, nullptr, 4 },
     { Event::DESTRUCT, &*o, nullptr, 4 },
   };
-  return retval;
+  return true;
 }
 
 int testOptional(int /*unused*/, char* /*unused*/ [])
@@ -691,6 +769,7 @@ int testOptional(int /*unused*/, char* /*unused*/ [])
   DO_EVENT_TEST(testHasValue);
   DO_EVENT_TEST(testValue);
   DO_TEST(testValueOr);
+  DO_EVENT_TEST(testComparison);
   DO_EVENT_TEST(testSwap);
   DO_EVENT_TEST(testReset);
   DO_EVENT_TEST(testEmplace);

+ 204 - 0
Utilities/std/cm/optional

@@ -218,6 +218,210 @@ optional<T>& optional<T>::operator=(U&& v)
   return *this;
 }
 
+template <typename T, typename U>
+bool operator==(const optional<T>& lhs, const optional<U>& rhs)
+{
+  if (lhs.has_value()) {
+    return rhs.has_value() && *lhs == *rhs;
+  }
+  return !rhs.has_value();
+}
+
+template <typename T, typename U>
+bool operator!=(const optional<T>& lhs, const optional<U>& rhs)
+{
+  if (lhs.has_value()) {
+    return !rhs.has_value() || *lhs != *rhs;
+  }
+  return rhs.has_value();
+}
+
+template <typename T, typename U>
+bool operator<(const optional<T>& lhs, const optional<U>& rhs)
+{
+  if (rhs.has_value()) {
+    return !lhs.has_value() || *lhs < *rhs;
+  }
+  return false;
+}
+
+template <typename T, typename U>
+bool operator<=(const optional<T>& lhs, const optional<U>& rhs)
+{
+  if (!lhs.has_value()) {
+    return true;
+  }
+  if (rhs.has_value()) {
+    return *lhs <= *rhs;
+  }
+  return false;
+}
+
+template <typename T, typename U>
+bool operator>(const optional<T>& lhs, const optional<U>& rhs)
+{
+  if (lhs.has_value()) {
+    return !rhs.has_value() || *lhs > *rhs;
+  }
+  return false;
+}
+
+template <typename T, typename U>
+bool operator>=(const optional<T>& lhs, const optional<U>& rhs)
+{
+  if (!rhs.has_value()) {
+    return true;
+  }
+  if (lhs.has_value()) {
+    return *lhs >= *rhs;
+  }
+  return false;
+}
+
+template <typename T>
+bool operator==(const optional<T>& opt, nullopt_t) noexcept
+{
+  return !opt.has_value();
+}
+
+template <typename T>
+bool operator!=(const optional<T>& opt, nullopt_t) noexcept
+{
+  return opt.has_value();
+}
+
+template <typename T>
+bool operator<(const optional<T>& opt, nullopt_t) noexcept
+{
+  return false;
+}
+
+template <typename T>
+bool operator<=(const optional<T>& opt, nullopt_t) noexcept
+{
+  return !opt.has_value();
+}
+
+template <typename T>
+bool operator>(const optional<T>& opt, nullopt_t) noexcept
+{
+  return opt.has_value();
+}
+
+template <typename T>
+bool operator>=(const optional<T>& opt, nullopt_t) noexcept
+{
+  return true;
+}
+
+template <typename T>
+bool operator==(nullopt_t, const optional<T>& opt) noexcept
+{
+  return !opt.has_value();
+}
+
+template <typename T>
+bool operator!=(nullopt_t, const optional<T>& opt) noexcept
+{
+  return opt.has_value();
+}
+
+template <typename T>
+bool operator<(nullopt_t, const optional<T>& opt) noexcept
+{
+  return opt.has_value();
+}
+
+template <typename T>
+bool operator<=(nullopt_t, const optional<T>& opt) noexcept
+{
+  return true;
+}
+
+template <typename T>
+bool operator>(nullopt_t, const optional<T>& opt) noexcept
+{
+  return false;
+}
+
+template <typename T>
+bool operator>=(nullopt_t, const optional<T>& opt) noexcept
+{
+  return !opt.has_value();
+}
+
+template <typename T, typename U>
+bool operator==(const optional<T>& opt, const U& value)
+{
+  return opt.has_value() && *opt == value;
+}
+
+template <typename T, typename U>
+bool operator!=(const optional<T>& opt, const U& value)
+{
+  return !opt.has_value() || *opt != value;
+}
+
+template <typename T, typename U>
+bool operator<(const optional<T>& opt, const U& value)
+{
+  return !opt.has_value() || *opt < value;
+}
+
+template <typename T, typename U>
+bool operator<=(const optional<T>& opt, const U& value)
+{
+  return !opt.has_value() || *opt <= value;
+}
+
+template <typename T, typename U>
+bool operator>(const optional<T>& opt, const U& value)
+{
+  return opt.has_value() && *opt > value;
+}
+
+template <typename T, typename U>
+bool operator>=(const optional<T>& opt, const U& value)
+{
+  return opt.has_value() && *opt >= value;
+}
+
+template <typename T, typename U>
+bool operator==(const T& value, const optional<U>& opt)
+{
+  return opt.has_value() && value == *opt;
+}
+
+template <typename T, typename U>
+bool operator!=(const T& value, const optional<U>& opt)
+{
+  return !opt.has_value() || value != *opt;
+}
+
+template <typename T, typename U>
+bool operator<(const T& value, const optional<U>& opt)
+{
+  return opt.has_value() && value < *opt;
+}
+
+template <typename T, typename U>
+bool operator<=(const T& value, const optional<U>& opt)
+{
+  return opt.has_value() && value <= *opt;
+}
+
+template <typename T, typename U>
+bool operator>(const T& value, const optional<U>& opt)
+{
+  return !opt.has_value() || value > *opt;
+}
+
+template <typename T, typename U>
+bool operator>=(const T& value, const optional<U>& opt)
+{
+  return !opt.has_value() || value >= *opt;
+}
+
 template <typename T>
 const T* optional<T>::operator->() const
 {