From cd5c8695e3b01787061cf02883d8b4241488c270 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Tue, 8 Aug 2023 06:39:01 +0100 Subject: [PATCH 1/5] Use C++20 for ""_s if available In C++20, we are supposed to use CTAD NTTPs to implement string UDL templates. Continue to use BOOST_HANA_CONFIG_ENABLE_STRING_UDL to indicate that the string UDL template is available, but enable that macro by default if C++20 is detected. --- CMakeLists.txt | 3 ++- example/string/literal.cpp | 2 +- include/boost/hana/config.hpp | 25 ++++++++++++++++-------- include/boost/hana/fwd/string.hpp | 32 ++++++++++++++++++++++--------- include/boost/hana/string.hpp | 25 ++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 016e78e25..197888d1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,8 @@ option(BOOST_HANA_ENABLE_DEBUG_MODE "Enable Hana's debug mode." OFF) option(BOOST_HANA_ENABLE_STRING_UDL "Enable the GNU extension allowing the special string literal operator\ - template, which enables the _s suffix for creating compile-time strings." ON) +template, which enables the _s suffix for creating compile-time strings\ +(unnecessary if you have a C++20 compiler)." ON) option(BOOST_HANA_ENABLE_EXCEPTIONS "Build with exceptions enabled. Note that Hana does not make use of exceptions,\ diff --git a/example/string/literal.cpp b/example/string/literal.cpp index b20e1dd71..237963f03 100644 --- a/example/string/literal.cpp +++ b/example/string/literal.cpp @@ -13,7 +13,7 @@ namespace hana = boost::hana; using namespace hana::literals; -// By default, this is disabled +// This requires C++20 or a compiler extension which is disabled by default #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL constexpr auto str = "Hello world!"_s; diff --git a/include/boost/hana/config.hpp b/include/boost/hana/config.hpp index 7b7805696..ffdf116cf 100644 --- a/include/boost/hana/config.hpp +++ b/include/boost/hana/config.hpp @@ -80,6 +80,11 @@ Distributed under the Boost Software License, Version 1.0. # endif #endif +#if (__cpp_deduction_guides >= 201907L) && \ + !defined(BOOST_HANA_CONFIG_ENABLE_STRING_UDL) +# define BOOST_HANA_CONFIG_ENABLE_STRING_UDL +#endif + ////////////////////////////////////////////////////////////////////////////// // Caveats and other compiler-dependent options ////////////////////////////////////////////////////////////////////////////// @@ -145,17 +150,21 @@ Distributed under the Boost Software License, Version 1.0. # define BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS #endif -#if defined(BOOST_HANA_DOXYGEN_INVOKED) +#if defined(BOOST_HANA_DOXYGEN_INVOKED) && \ + !defined(BOOST_HANA_CONFIG_ENABLE_STRING_UDL) //! @ingroup group-config - //! Enables usage of the "string literal operator template" GNU extension. + //! Enables usage of the "string literal operator template" GNU extension + //! before C++20. //! - //! That operator is not part of the language yet, but it is supported by - //! both Clang and GCC. This operator allows Hana to provide the nice `_s` - //! user-defined literal for creating compile-time strings. + //! C++20 added functionality allowing Hana to provide the nice `_s` + //! user-defined literal for creating compile-time strings; prior to that, + //! both Clang and GCC supported an extension allowing the same + //! functionality but via a different mechanism. //! - //! When this macro is not defined, the GNU extension will be not used - //! by Hana. Because this is a non-standard extension, the macro is not - //! defined by default. + //! When C++20 support is detected, this macro is defined by default and + //! the C++20 mechanism is used. Otherwise, if this macro is not defined, + //! the macro is not defined by default and the GNU extension will not be + //! used by Hana because it is a non-standard extension. # define BOOST_HANA_CONFIG_ENABLE_STRING_UDL #endif diff --git a/include/boost/hana/fwd/string.hpp b/include/boost/hana/fwd/string.hpp index 91ee4de57..c26804078 100644 --- a/include/boost/hana/fwd/string.hpp +++ b/include/boost/hana/fwd/string.hpp @@ -233,13 +233,21 @@ namespace boost { namespace hana { #endif #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL +# if (__cpp_deduction_guides >= 201907L) + namespace string_detail { + template + struct literal_helper; + } +# endif + namespace literals { //! Creates a compile-time string from a string literal. //! @relatesalso boost::hana::string //! //! The string literal is parsed at compile-time and the result is - //! returned as a `hana::string`. This feature is an extension that - //! is disabled by default; see below for details. + //! returned as a `hana::string`. This feature requires C++20 or a + //! compiler extension that is disabled by default; see below for + //! details. //! //! @note //! Only narrow string literals are supported right now; support for @@ -249,14 +257,15 @@ namespace boost { namespace hana { //! //! @warning //! This user-defined literal is an extension which requires a special - //! string literal operator that is not part of the standard yet. - //! That operator is supported by both Clang and GCC, and several - //! proposals were made for it to enter C++17. However, since it is - //! not standard, it is disabled by default and defining the + //! string literal operator that was added to the standard in C++20. + //! Prior to that, it is supported by both Clang and GCC, with slightly + //! different syntax. Since it is not standard, it is disabled by + //! default in pre=C++20 mode and defining the //! `BOOST_HANA_CONFIG_ENABLE_STRING_UDL` config macro is required - //! to get this operator. Hence, if you want to stay safe, just use - //! the `BOOST_HANA_STRING` macro instead. If you want to be fast and - //! furious (I do), define `BOOST_HANA_CONFIG_ENABLE_STRING_UDL`. + //! to get this operator. Hence, if you do not have C++20 and want to + //! stay safe, just use the `BOOST_HANA_STRING` macro instead. If you + //! want to be fast and furious (I do), define + //! `BOOST_HANA_CONFIG_ENABLE_STRING_UDL`. //! //! //! Example @@ -264,8 +273,13 @@ namespace boost { namespace hana { //! @include example/string/literal.cpp //! //! [Hana.issue80]: https://github.com/boostorg/hana/issues/80 +# if (__cpp_deduction_guides >= 201907L) + template + constexpr auto operator"" _s(); +# else template constexpr auto operator"" _s(); +# endif } #endif }} // end namespace boost::hana diff --git a/include/boost/hana/string.hpp b/include/boost/hana/string.hpp index 7c1c4741d..cf8e625e0 100644 --- a/include/boost/hana/string.hpp +++ b/include/boost/hana/string.hpp @@ -109,10 +109,34 @@ namespace boost { namespace hana { /**/ #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL +# if (__cpp_deduction_guides >= 201907L) + namespace string_detail { + template + struct literal_helper { + constexpr literal_helper(char const (&s)[N]) { + for (std::size_t i = 0; i != N; ++i) + buf[i] = s[i]; + } + static constexpr unsigned size() { return N - 1; } + char buf[N]; + }; + template + literal_helper(char const (&)[N]) -> literal_helper; + } +# endif + ////////////////////////////////////////////////////////////////////////// // _s user-defined literal ////////////////////////////////////////////////////////////////////////// namespace literals { +# if (__cpp_deduction_guides >= 201907L) + template + constexpr auto operator""_s() { + return [](std::index_sequence) { + return hana::string_c; + }(std::make_index_sequence()); + } +# else template constexpr auto operator"" _s() { static_assert(std::is_same::value, @@ -121,6 +145,7 @@ namespace boost { namespace hana { "if you need support for fancier types of compile-time strings."); return hana::string_c; } +# endif } #endif From 110cbcb54ce1a9cd041b82fd0c0f2f0901a3a6d0 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Tue, 8 Aug 2023 17:19:08 -0500 Subject: [PATCH 2/5] formatting --- include/boost/hana/string.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/hana/string.hpp b/include/boost/hana/string.hpp index cf8e625e0..d36f87da2 100644 --- a/include/boost/hana/string.hpp +++ b/include/boost/hana/string.hpp @@ -131,7 +131,7 @@ namespace boost { namespace hana { namespace literals { # if (__cpp_deduction_guides >= 201907L) template - constexpr auto operator""_s() { + constexpr auto operator"" _s() { return [](std::index_sequence) { return hana::string_c; }(std::make_index_sequence()); From 79b8f55592e4048bd016aaeaec293f6faac85ec5 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Wed, 9 Aug 2023 00:38:02 +0100 Subject: [PATCH 3/5] Fix detection of C++20 string UDL support --- include/boost/hana/config.hpp | 27 ++++++++++++++++++++++++++- include/boost/hana/fwd/string.hpp | 26 +++++++++++++++----------- include/boost/hana/string.hpp | 6 +++--- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/include/boost/hana/config.hpp b/include/boost/hana/config.hpp index ffdf116cf..732b20532 100644 --- a/include/boost/hana/config.hpp +++ b/include/boost/hana/config.hpp @@ -80,11 +80,36 @@ Distributed under the Boost Software License, Version 1.0. # endif #endif -#if (__cpp_deduction_guides >= 201907L) && \ +////////////////////////////////////////////////////////////////////////////// +// C++20 string literal UDL suport +////////////////////////////////////////////////////////////////////////////// +#if defined(_MSC_VER) && !defined(__clang__) +# if _MSVC_LANG > 201703 && _MSC_FULL_VER >= 192829921 +# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL +# endif +#elif defined(__clang__) +# if (__cplusplus > 201703 && \ + BOOST_HANA_CONFIG_CLANG >= BOOST_HANA_CONFIG_VERSION(12, 0, 0)) +# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL +# if BOOST_HANA_CONFIG_CLANG < BOOST_HANA_CONFIG_VERSION(18, 0, 0) +# define BOOST_HANA_CONFIG_CXX20_STRING_UDL_CLANG_WORKAROUND +# endif +# endif +#elif defined(__GNUC__) +# if (__cplusplus > 201703 && \ + BOOST_HANA_CONFIG_GCC >= BOOST_HANA_CONFIG_VERSION(9, 3, 0)) +# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL +# endif +#elif (__cpp_deduction_guides >= 201703 && \ + __cpp_nontype_template_args >= 201911) +# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL +#endif +#if defined(BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL) && \ !defined(BOOST_HANA_CONFIG_ENABLE_STRING_UDL) # define BOOST_HANA_CONFIG_ENABLE_STRING_UDL #endif + ////////////////////////////////////////////////////////////////////////////// // Caveats and other compiler-dependent options ////////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/hana/fwd/string.hpp b/include/boost/hana/fwd/string.hpp index c26804078..b983ade56 100644 --- a/include/boost/hana/fwd/string.hpp +++ b/include/boost/hana/fwd/string.hpp @@ -233,7 +233,7 @@ namespace boost { namespace hana { #endif #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL -# if (__cpp_deduction_guides >= 201907L) +# ifdef BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL namespace string_detail { template struct literal_helper; @@ -256,15 +256,14 @@ namespace boost { namespace hana { //! [Hana.issue80] if you need this. //! //! @warning - //! This user-defined literal is an extension which requires a special - //! string literal operator that was added to the standard in C++20. - //! Prior to that, it is supported by both Clang and GCC, with slightly - //! different syntax. Since it is not standard, it is disabled by - //! default in pre=C++20 mode and defining the - //! `BOOST_HANA_CONFIG_ENABLE_STRING_UDL` config macro is required - //! to get this operator. Hence, if you do not have C++20 and want to - //! stay safe, just use the `BOOST_HANA_STRING` macro instead. If you - //! want to be fast and furious (I do), define + //! This user-defined literal requires a special string literal operator + //! that was added to the standard in C++20. Prior to that, an extension + //! supported by both Clang and GCC provides similar functionality, but + //! since it is not standard, it is disabled by default in pre=C++20 + //! mode and defining the `BOOST_HANA_CONFIG_ENABLE_STRING_UDL` config + //! macro is required to get this operator. Hence, if you do not have + //! C++20 and want to stay safe, just use the `BOOST_HANA_STRING` macro + //! instead. If you want to be fast and furious (I do), define //! `BOOST_HANA_CONFIG_ENABLE_STRING_UDL`. //! //! @@ -273,7 +272,12 @@ namespace boost { namespace hana { //! @include example/string/literal.cpp //! //! [Hana.issue80]: https://github.com/boostorg/hana/issues/80 -# if (__cpp_deduction_guides >= 201907L) +# if defined(BOOST_HANA_DOXYGEN_INVOKED) + template + constexpr auto operator"" _s(); +# elif defined(BOOST_HANA_CONFIG_CXX20_STRING_UDL_CLANG_WORKAROUND) + // Older versions of clang get confused by a forward declaration. +# elif defined(BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL) template constexpr auto operator"" _s(); # else diff --git a/include/boost/hana/string.hpp b/include/boost/hana/string.hpp index d36f87da2..b1e9da6d2 100644 --- a/include/boost/hana/string.hpp +++ b/include/boost/hana/string.hpp @@ -109,7 +109,7 @@ namespace boost { namespace hana { /**/ #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL -# if (__cpp_deduction_guides >= 201907L) +# ifdef BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL namespace string_detail { template struct literal_helper { @@ -118,7 +118,7 @@ namespace boost { namespace hana { buf[i] = s[i]; } static constexpr unsigned size() { return N - 1; } - char buf[N]; + char buf[N] = {}; }; template literal_helper(char const (&)[N]) -> literal_helper; @@ -129,7 +129,7 @@ namespace boost { namespace hana { // _s user-defined literal ////////////////////////////////////////////////////////////////////////// namespace literals { -# if (__cpp_deduction_guides >= 201907L) +# ifdef BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL template constexpr auto operator"" _s() { return [](std::index_sequence) { From 2352f1a97f02ac1ec5c4b9c4d68401ce2d1be94f Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Wed, 9 Aug 2023 00:40:15 +0100 Subject: [PATCH 4/5] use unsigned in ctor for consistency --- include/boost/hana/string.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/hana/string.hpp b/include/boost/hana/string.hpp index b1e9da6d2..b2d0e06db 100644 --- a/include/boost/hana/string.hpp +++ b/include/boost/hana/string.hpp @@ -114,7 +114,7 @@ namespace boost { namespace hana { template struct literal_helper { constexpr literal_helper(char const (&s)[N]) { - for (std::size_t i = 0; i != N; ++i) + for (unsigned i = 0; i != N; ++i) buf[i] = s[i]; } static constexpr unsigned size() { return N - 1; } From 9502d00c4f7088e93ecbf06e0355c8d6a028aba8 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Wed, 9 Aug 2023 00:41:34 +0100 Subject: [PATCH 5/5] formatting --- include/boost/hana/config.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/hana/config.hpp b/include/boost/hana/config.hpp index 732b20532..2ffbc9ec4 100644 --- a/include/boost/hana/config.hpp +++ b/include/boost/hana/config.hpp @@ -109,7 +109,6 @@ Distributed under the Boost Software License, Version 1.0. # define BOOST_HANA_CONFIG_ENABLE_STRING_UDL #endif - ////////////////////////////////////////////////////////////////////////////// // Caveats and other compiler-dependent options //////////////////////////////////////////////////////////////////////////////