lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] master d74e38e 4/5: Move some documentation; add som


From: Greg Chicares
Subject: [lmi-commits] [lmi] master d74e38e 4/5: Move some documentation; add some experiments
Date: Mon, 11 Jun 2018 19:54:38 -0400 (EDT)

branch: master
commit d74e38ed29343e82d7c7a0c88effccca42025110
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Move some documentation; add some experiments
---
 ssize_lmi.hpp      |  33 ------------
 ssize_lmi_test.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+), 33 deletions(-)

diff --git a/ssize_lmi.hpp b/ssize_lmi.hpp
index 3f561d4..9761b30 100644
--- a/ssize_lmi.hpp
+++ b/ssize_lmi.hpp
@@ -82,39 +82,6 @@
 /// Question: "...it's gonna pollute, right?"
 /// Carruth: "We're sorry."
 /// Sutter: "As Scott would say, 'we were young'."
-///
-/// Implementation notes.
-///
-/// An array-bound parameter can be deduced as a signed integer: the
-/// deduced value need not be unsigned. See C++17 (N4659) [17.8.2.1]
-/// (i.e., [temp.deduc.call]):
-///
-/// | template<class T, int N> void h(T const(&)[N]);
-/// | h({1,2,3}); // T deduced to int, N deduced to 3
-///
-/// However, the array bound is of type std::size_t [17.8.2.5]
-/// (i.e., [temp.deduct.type]):
-///
-/// | The type of N in the type T[N] is std::size_t.
-///
-/// Presumably deduction works as if:
-///
-///   // explicit type of 'n' is signed char
-///   // deduced value of 'n' is an ICE
-///   // initialization is an error if the conversion is narrowing
-///   //
-///   template<typename T, signed char n>
-///   constexpr signed char foo(T const(&)[n])
-///   {
-///       n = signed char({ICE_deduced_for_n});
-///   }
-///
-/// and the compiler should emit a diagnostic if an array with more
-/// than SCHAR_MAX elements is passed. Because the standard does not
-/// specify this precisely, it seems best to use type std::size_t for
-/// array-bound template parameters and convert their values to the
-/// desired return type using a facility such as bourn_cast or a
-/// braced-init-list that ensures value preservation.
 
 namespace lmi
 {
diff --git a/ssize_lmi_test.cpp b/ssize_lmi_test.cpp
index 690a398..d367db5 100644
--- a/ssize_lmi_test.cpp
+++ b/ssize_lmi_test.cpp
@@ -24,14 +24,163 @@
 #include "ssize_lmi.hpp"
 
 #include "bourn_cast.hpp"
+#include "rtti_lmi.hpp"
 #include "test_tools.hpp"
 
 #include <array>
+#include <climits>                      // CHAR_MAX
 #include <cstring>                      // strlen()
 #include <iterator>                     // size()
 #include <string>
 #include <vector>
 
+/// Experimental investigation of array-bound deduction.
+///
+/// An array-bound parameter can be deduced as a signed integer: the
+/// deduced value need not be unsigned. See C++17 (N4659) [17.8.2.1]
+/// (i.e., [temp.deduc.call]):
+///
+/// | template<class T, int N> void h(T const(&)[N]);
+/// | h({1,2,3}); // T deduced to int, N deduced to 3
+///
+/// However, the array bound is of type std::size_t [17.8.2.5]
+/// (i.e., [temp.deduct.type]):
+///
+/// | The type of N in the type T[N] is std::size_t.
+///
+/// Presumably deduction works as if:
+///
+///   // explicit type of 'n' is signed char
+///   // deduced value of 'n' is an ICE
+///   // initialization is an error if the conversion is narrowing
+///   //
+///   template<typename T, signed char n>
+///   constexpr signed char foo(T const(&)[n])
+///   {
+///       n = signed char({ICE_deduced_for_n});
+///   }
+///
+/// and the compiler should emit a diagnostic if an array with more
+/// than SCHAR_MAX elements is passed. Because the standard does not
+/// specify this precisely, it seems best to use type std::size_t for
+/// array-bound template parameters and convert their values to the
+/// desired return type using a facility such as bourn_cast or a
+/// braced-init-list that ensures value preservation.
+///
+/// In the sample implementation above, 'const' on the unnamed array
+/// parameter means nothing, and is omitted in the examples below; it
+/// is specified in the header tested here to document that const
+/// arrays are handled correctly. Similarly, 'constexpr' serves only
+/// a documentary purpose, because an ICE is already a compile-time
+/// constant.
+///
+/// Conclusions drawn from the experiments below.
+///
+/// With i686-w64-mingw32-gcc-7.3, evidently the non-type parameter
+/// is deduced to have a value that is always an ICE of type int,
+/// not type std::size_t. It is then progressively converted to the
+/// integral type specified in the template-parameter-list, and then
+/// to the return type, eliciting a diagnostic if the value cannot be
+/// preserved. Comments beginning 'error:' are extracted from actual
+/// gcc diagnostics.
+///
+/// Using bourn_cast<>() in the implementation turns an informative
+/// compile-time diagnostic into a runtime exception, so that's just
+/// a poor idea. Using a braced-init-list in the body of the function
+/// template gives the most useful diagnostic, so f0g() seems best, at
+/// least with this particular compiler. The template-parameter-list
+/// might specify std::size_t for the non-type parameter, especially
+/// in light of the [temp.deduct.type] quote above, but it seems even
+/// better to use auto, again as in f0g(), and to specify the return
+/// type of lmi::ssize() as the signed analogue of std::size_t.
+
+namespace experimental
+{
+// deduce char, return int
+// here gcc further reports:
+// | In substitution of 'template<class T, char n>
+// | int experimental::f0a(T (&)[n])
+// | [with T = const float; char n = '\37777777600']'
+// a web search for that octal constant finds references to
+//   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77573
+// | bogus wide string literals in diagnostics
+// so that extra information is not actually very helpful
+template<typename T, char n>
+int f0a(T(&)[n]) // error: overflow in constant expression
+{
+    return bourn_cast<int>(n);
+}
+
+// deduce int, return char; not constexpr
+template<typename T, int n>
+char f0b(T(&)[n])
+{
+    return bourn_cast<char>(n);
+}
+
+// deduce int, return char; constexpr (makes no difference)
+template<typename T, int n>
+constexpr char f0c(T(&)[n])
+{
+    return bourn_cast<char>(n);
+}
+
+// deduce int, return char; braced-init-list
+template<typename T, int n>
+char f0d(T(&)[n])
+{
+    return {n}; // error: narrowing conversion of '128' from 'int' to 'char'
+}
+
+// deduce short int, return char; braced-init-list
+template<typename T, short int n>
+char f0e(T(&)[n])
+{
+    return {n}; // error: narrowing conversion of '128' from 'short int'
+}
+
+// deduce std::size_t, return char; braced-init-list
+template<typename T, std::size_t n>
+char f0f(T(&)[n])
+{
+    return {n}; // error: narrowing conversion of '128' from 'unsigned int'
+}
+
+// deduce auto, return char; braced-init-list
+// auto is deduced to int, not to std::size_t
+template<typename T, auto n>
+char f0g(T(&)[n])
+{
+    return {n}; // error: narrowing conversion of '128' from 'int' to 'char'
+}
+
+// deduce auto, return deduced type
+// auto is deduced to int, not to std::size_t
+template<typename T, auto n>
+auto f0h(T(&)[n])
+{
+    std::cout << "Expect something like 'int' to be printed:" << std::endl;
+    std::cout << lmi::TypeInfo(typeid(n)) << std::endl; // prints "int"
+//  return {n}; // error: returning initializer list
+    return n;
+}
+
+void test_array_bound_deduction()
+{
+    std::size_t const array_size = std::size_t(1) + CHAR_MAX;
+    float const array[array_size] {};
+//  f0a(array); // compile-time error
+//  f0b(array); // run-time error
+//  f0c(array); // run-time error
+//  f0d(array); // compile-time error
+//  f0e(array); // compile-time error
+//  f0f(array); // compile-time error
+//  f0g(array); // compile-time error
+    f0h(array);
+    lmi::ssize(array);
+}
+} // namespace experimental
+
 void test_various_containers()
 {
     char const c[2] = {'0'};
@@ -57,6 +206,7 @@ void test_various_containers()
 
 int test_main(int, char*[])
 {
+    experimental::test_array_bound_deduction();
     test_various_containers();
 
     return 0;



reply via email to

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