* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) [not found] <CAGNvRgCv1Y8a6DGO=p9g8FAve1-UKf53vshqFYtdmWkDUzn8+Q@mail.gmail.com> @ 2017-07-28 20:26 ` Tim Song 2017-07-28 20:29 ` Daniel Krügler 0 siblings, 1 reply; 12+ messages in thread From: Tim Song @ 2017-07-28 20:26 UTC (permalink / raw) To: Daniel Krügler; +Cc: libstdc++, gcc-patches On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler <daniel.kruegler@gmail.com> wrote: > + // Performs an implicit conversion from _Tp to __sv_type. > + template<typename _Tp> > + static __sv_type _S_to_string_view(const _Tp& __svt) > + { > + return __svt; > + } I might have gone for + static __sv_type _S_to_string_view(__sv_type __svt) noexcept + { + return __svt; + } With that, we can also use noexcept(_S_to_string_view(__t)) to make up for the absence of is_nothrow_convertible (basically the same thing I did in LWG 2993's PR). Tim ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-07-28 20:26 ` [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) Tim Song @ 2017-07-28 20:29 ` Daniel Krügler 2017-07-28 20:40 ` Daniel Krügler 0 siblings, 1 reply; 12+ messages in thread From: Daniel Krügler @ 2017-07-28 20:29 UTC (permalink / raw) To: Tim Song; +Cc: libstdc++, gcc-patches 2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: > On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler > <daniel.kruegler@gmail.com> wrote: >> + // Performs an implicit conversion from _Tp to __sv_type. >> + template<typename _Tp> >> + static __sv_type _S_to_string_view(const _Tp& __svt) >> + { >> + return __svt; >> + } > > I might have gone for > > + static __sv_type _S_to_string_view(__sv_type __svt) noexcept > + { > + return __svt; > + } > > With that, we can also use noexcept(_S_to_string_view(__t)) to make up > for the absence of is_nothrow_convertible (basically the same thing I > did in LWG 2993's PR). Agreed, that makes very much sense. I will adjust the P/R, but before I resubmit I would like to get feedback whether the other two compare functions also should become conditionally noexcept. Thanks, - Daniel ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-07-28 20:29 ` Daniel Krügler @ 2017-07-28 20:40 ` Daniel Krügler 2017-07-30 13:01 ` Daniel Krügler 0 siblings, 1 reply; 12+ messages in thread From: Daniel Krügler @ 2017-07-28 20:40 UTC (permalink / raw) To: Tim Song; +Cc: libstdc++, gcc-patches 2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: > 2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >> On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >> <daniel.kruegler@gmail.com> wrote: >>> + // Performs an implicit conversion from _Tp to __sv_type. >>> + template<typename _Tp> >>> + static __sv_type _S_to_string_view(const _Tp& __svt) >>> + { >>> + return __svt; >>> + } >> >> I might have gone for >> >> + static __sv_type _S_to_string_view(__sv_type __svt) noexcept >> + { >> + return __svt; >> + } >> >> With that, we can also use noexcept(_S_to_string_view(__t)) to make up >> for the absence of is_nothrow_convertible (basically the same thing I >> did in LWG 2993's PR). > > Agreed, that makes very much sense. I will adjust the P/R, but before > I resubmit I would like to get feedback whether the other two compare > functions also should become conditionally noexcept. Locally I have now performed the sole change of the _S_to_string_view declaration getting rid of the template, but would also like to gather feedback from the maintainers whether I should also change the form of the conditional noexcept to use the expression noexcept(_S_to_string_view(__t)) instead of the current is_same<_Tp, __sv_type>::value as suggested by Tim Song. I'm asking also, because I have a paper proposing to standardize is_nothrow_convertible submitted for the upcoming C++ mailing - This would be one of the first applications in the library ;-) > Thanks, > > - Daniel ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-07-28 20:40 ` Daniel Krügler @ 2017-07-30 13:01 ` Daniel Krügler 2017-08-18 18:27 ` Daniel Krügler 2017-09-04 15:48 ` Jonathan Wakely 0 siblings, 2 replies; 12+ messages in thread From: Daniel Krügler @ 2017-07-30 13:01 UTC (permalink / raw) To: Tim Song; +Cc: libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 2166 bytes --] 2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: > 2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >> 2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>> On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>> <daniel.kruegler@gmail.com> wrote: >>>> + // Performs an implicit conversion from _Tp to __sv_type. >>>> + template<typename _Tp> >>>> + static __sv_type _S_to_string_view(const _Tp& __svt) >>>> + { >>>> + return __svt; >>>> + } >>> >>> I might have gone for >>> >>> + static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>> + { >>> + return __svt; >>> + } >>> >>> With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>> for the absence of is_nothrow_convertible (basically the same thing I >>> did in LWG 2993's PR). >> >> Agreed, that makes very much sense. I will adjust the P/R, but before >> I resubmit I would like to get feedback whether the other two compare >> functions also should become conditionally noexcept. > > Locally I have now performed the sole change of the _S_to_string_view > declaration getting rid of the template, but would also like to gather > feedback from the maintainers whether I should also change the form of > the conditional noexcept to use the expression > > noexcept(_S_to_string_view(__t)) > > instead of the current > > is_same<_Tp, __sv_type>::value > > as suggested by Tim Song. > > I'm asking also, because I have a paper proposing to standardize > is_nothrow_convertible submitted for the upcoming C++ mailing - This > would be one of the first applications in the library ;-) A slightly revised patch update: It replaces the _S_to_string_view template by a simpler _S_to_string_view function as of Tim Song's suggestion, but still uses the simplified noexcept specification deferring it to a future application case for is_nothrow_convertible. Furthermore now all three compare function templates are now (conditionally) noexcept by an (off-list) suggestion from Jonathan Wakely. Thanks, - Daniel [-- Attachment #2: ChangeLog_79162.patch --] [-- Type: application/octet-stream, Size: 2161 bytes --] Index: libstdc++-v3/ChangeLog =================================================================== --- libstdc++-v3/ChangeLog (revision 250720) +++ libstdc++-v3/ChangeLog (working copy) @@ -1,3 +1,34 @@ +2017-07-30 Daniel Kruegler <daniel.kruegler@gmail.com> + + PR libstdc++/79162 + Implement LWG 2946, LWG 2758's resolution missed further corrections + * include/bits/basic_string.h (basic_string::compare): Add missing + required noexcept specifications. + * include/bits/basic_string.h (basic_string): Introduce internal + _S_to_string_view and __sv_wrapper for implicit string_view conversion. + * include/bits/basic_string.h (basic_string::basic_string): Fix explicit + string_view conversion by implicit conversion using _S_to_string_view and + __sv_wrapper. + * include/bits/basic_string.h (basic_string): Introduce internal + basic_string(__sv_wrapper, Alloc) constructor. + * include/bits/basic_string.h (basic_string): Fix operator=(T) template + by operator=(const T&) template for uncopyable types (79162). + * include/bits/basic_string.h (basic_string::operator+=, + basic_string::append, basic_string::assign, basic_string::insert, + basic_string::replace, basic_string::find, basic_string::rfind, + basic_string::find_first_of, basic_string::find_last_of, + basic_string::find_first_not_of, basic_string::find_last_not_of, + basic_string::compare): Replace __sv_type argument by template const T& + (LWG 2946) and correct documentation describing __sv_type argument. + * include/bits/basic_string.h (basic_string::find, basic_string::rfind, + basic_string::find_first_of, basic_string::find_last_of, + basic_string::find_first_not_of, basic_string::find_last_not_of, + basic_string::compare): Replace unconditional noexcept specification by + conditional noexcept specification to partially balance the remove of + noexcept by LWG 2946. + * testsuite/21_strings/basic_string/79162.cc: New. + * testsuite/21_strings/basic_string/lwg2946.cc: New. + 2017-07-26 Jonathan Wakely <jwakely@redhat.com> * testsuite/27_io/basic_fstream/53984.cc: Fix test. [-- Attachment #3: 79162.patch --] [-- Type: application/octet-stream, Size: 43088 bytes --] Index: libstdc++-v3/include/bits/basic_string.h =================================================================== --- libstdc++-v3/include/bits/basic_string.h (revision 250720) +++ libstdc++-v3/include/bits/basic_string.h (working copy) @@ -117,6 +117,22 @@ __and_<is_convertible<const _Tp&, __sv_type>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; + + // Allows an implicit conversion to __sv_type. + static __sv_type _S_to_string_view(__sv_type __svt) noexcept + { + return __svt; + } + + // Wraps a string_view by explicit conversion and thus + // allows to add an internal constructor that does not + // participate in overload resolution when a string_view + // is provided. + struct __sv_wrapper + { + explicit __sv_wrapper(__sv_type __sv) noexcept : _M_sv(__sv) {} + __sv_type _M_sv; + }; #endif // Use empty-base optimization: http://www.cantrip.org/emptyopt.html @@ -593,7 +609,7 @@ #if __cplusplus > 201402L /** * @brief Construct string from a substring of a string_view. - * @param __t Source string view. + * @param __t Source object convertible to string view. * @param __pos The index of the first character to copy from __t. * @param __n The number of characters to copy from __t. * @param __a Allocator to use. @@ -601,16 +617,27 @@ template<typename _Tp, typename = _If_sv<_Tp, void>> basic_string(const _Tp& __t, size_type __pos, size_type __n, const _Alloc& __a = _Alloc()) - : basic_string(__sv_type(__t).substr(__pos, __n), __a) { } - + : basic_string(_S_to_string_view(__t).substr(__pos, __n), __a) { } + /** * @brief Construct string from a string_view. - * @param __sv Source string view. + * @param __t Source object convertible to string view. * @param __a Allocator to use (default is default allocator). */ + template<typename _Tp, typename = _If_sv<_Tp, void>> explicit - basic_string(__sv_type __sv, const _Alloc& __a = _Alloc()) - : basic_string(__sv.data(), __sv.size(), __a) { } + basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) + : basic_string(__sv_wrapper(_S_to_string_view(__t)), __a) { } + + /** + * @brief Only internally used: Construct string from a string view + * wrapper. + * @param __svw string view wrapper. + * @param __a Allocator to use. + */ + explicit + basic_string(__sv_wrapper __svw, const _Alloc& __a) + : basic_string(__svw._M_sv.data(), __svw._M_sv.size(), __a) { } #endif // C++17 /** @@ -756,12 +783,12 @@ #if __cplusplus > 201402L /** * @brief Set value to string constructed from a string_view. - * @param __sv A string_view. + * @param __svt An object convertible to string_view. */ - template<typename _Tp> - _If_sv<_Tp, basic_string&> - operator=(_Tp __sv) - { return this->assign(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator=(const _Tp& __svt) + { return this->assign(__svt); } /** * @brief Convert to a string_view. @@ -1157,12 +1184,13 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt An object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - operator+=(__sv_type __sv) - { return this->append(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator+=(const _Tp& __svt) + { return this->append(__svt); } #endif // C++17 /** @@ -1265,29 +1293,33 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt An object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - append(__sv_type __sv) - { return this->append(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->append(__sv.data(), __sv.size()); + } /** * @brief Append a range of characters from a string_view. - * @param __sv The string_view to be appended from. + * @param __svt An object convertible to string_view to be appended from. * @param __pos The position in the string_view to append from. * @param __n The number of characters to append from the string_view. * @return Reference to this string. */ template <typename _Tp> - _If_sv<_Tp, basic_string&> - append(const _Tp& __svt, size_type __pos, size_type __n = npos) - { - __sv_type __sv = __svt; - return _M_append(__sv.data() + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt, size_type __pos, size_type __n = npos) + { + __sv_type __sv = __svt; + return _M_append(__sv.data() + __sv._M_check(__pos, "basic_string::append"), __sv._M_limit(__pos, __n)); - } + } #endif // C++17 /** @@ -1433,29 +1465,33 @@ #if __cplusplus > 201402L /** * @brief Set value from a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @return Reference to this string. */ - basic_string& - assign(__sv_type __sv) - { return this->assign(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->assign(__sv.data(), __sv.size()); + } /** * @brief Set value from a range of characters in a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @param __pos The position in the string_view to assign from. * @param __n The number of characters to assign. * @return Reference to this string. */ - template <typename _Tp> - _If_sv<_Tp, basic_string&> - assign(const _Tp& __svt, size_type __pos, size_type __n = npos) - { - __sv_type __sv = __svt; - return _M_replace(size_type(0), this->size(), __sv.data() + template <typename _Tp> + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt, size_type __pos, size_type __n = npos) + { + __sv_type __sv = __svt; + return _M_replace(size_type(0), this->size(), __sv.data() + __sv._M_check(__pos, "basic_string::assign"), __sv._M_limit(__pos, __n)); - } + } #endif // C++17 #if __cplusplus >= 201103L @@ -1692,32 +1728,36 @@ /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - insert(size_type __pos, __sv_type __sv) - { return this->insert(__pos, __sv.data(), __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, basic_string&> + insert(size_type __pos, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->insert(__pos, __sv.data(), __sv.size()); + } /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos Iterator referencing position in string_view to insert * from. * @param __n The number of characters to insert. * @return Reference to this string. */ - template <typename _Tp> - _If_sv<_Tp, basic_string&> - insert(size_type __pos1, const _Tp& __svt, + template <typename _Tp> + _If_sv<_Tp, basic_string&> + insert(size_type __pos1, const _Tp& __svt, size_type __pos2, size_type __n = npos) - { - __sv_type __sv = __svt; - return this->replace(__pos1, size_type(0), __sv.data() + { + __sv_type __sv = __svt; + return this->replace(__pos1, size_type(0), __sv.data() + __sv._M_check(__pos2, "basic_string::insert"), __sv._M_limit(__pos2, __n)); - } + } #endif // C++17 /** @@ -2120,32 +2160,36 @@ * @brief Replace range of characters with string_view. * @param __pos The position to replace at. * @param __n The number of characters to replace. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - replace(size_type __pos, size_type __n, __sv_type __sv) - { return this->replace(__pos, __n, __sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + replace(size_type __pos, size_type __n, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__pos, __n, __sv.data(), __sv.size()); + } /** * @brief Replace range of characters with string_view. * @param __pos1 The position to replace at. * @param __n1 The number of characters to replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos2 The position in the string_view to insert from. * @param __n2 The number of characters to insert. * @return Reference to this string. */ - template <typename _Tp> - _If_sv<_Tp, basic_string&> - replace(size_type __pos1, size_type __n1, const _Tp& __svt, + template <typename _Tp> + _If_sv<_Tp, basic_string&> + replace(size_type __pos1, size_type __n1, const _Tp& __svt, size_type __pos2, size_type __n2 = npos) - { - __sv_type __sv = __svt; - return this->replace(__pos1, __n1, __sv.data() + { + __sv_type __sv = __svt; + return this->replace(__pos1, __n1, __sv.data() + __sv._M_check(__pos2, "basic_string::replace"), __sv._M_limit(__pos2, __n2)); - } + } /** * @brief Replace range of characters with string_view. @@ -2153,12 +2197,16 @@ to replace at. * @param __i2 An iterator referencing the end position for the replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @return Reference to this string. */ - basic_string& - replace(const_iterator __i1, const_iterator __i2, __sv_type __sv) - { return this->replace(__i1 - begin(), __i2 - __i1, __sv); } + template <typename _Tp> + _If_sv<_Tp, basic_string&> + replace(const_iterator __i1, const_iterator __i2, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__i1 - begin(), __i2 - __i1, __sv); + } #endif // C++17 private: @@ -2288,13 +2336,18 @@ #if __cplusplus > 201402L /** * @brief Find position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search from (default 0). * @return Index of start of first occurrence. */ - size_type - find(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2345,13 +2398,18 @@ #if __cplusplus > 201402L /** * @brief Find last position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search back from (default end). * @return Index of start of last occurrence. */ - size_type - rfind(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->rfind(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + rfind(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->rfind(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2419,13 +2477,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character of a string_view. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_first_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2497,13 +2561,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character of string. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_last_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2574,13 +2644,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt A object convertible to string_view containing characters + * to avoid. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_not_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_not_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_first_not_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2650,13 +2726,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt An object convertible to string_view containing + * characters to avoid. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_not_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_not_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_last_not_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2754,12 +2836,14 @@ #if __cplusplus > 201402L /** * @brief Compare to a string_view. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare against. * @return Integer < 0, 0, or > 0. */ - int - compare(__sv_type __sv) const + template <typename _Tp> + _If_sv<_Tp, int> + compare(const _Tp& __svt) const noexcept(is_same<_Tp, __sv_type>::value) { + __sv_type __sv = __svt; const size_type __size = this->size(); const size_type __osize = __sv.size(); const size_type __len = std::min(__size, __osize); @@ -2774,31 +2858,39 @@ * @brief Compare to a string_view. * @param __pos A position in the string to start comparing from. * @param __n The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @return Integer < 0, 0, or > 0. */ - int - compare(size_type __pos, size_type __n, __sv_type __sv) const - { return __sv_type(*this).substr(__pos, __n).compare(__sv); } + template <typename _Tp> + _If_sv<_Tp, int> + compare(size_type __pos, size_type __n, const _Tp& __svt) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return __sv_type(*this).substr(__pos, __n).compare(__sv); + } /** * @brief Compare to a string_view. * @param __pos1 A position in the string to start comparing from. * @param __n1 The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @param __pos2 A position in the string_view to start comparing from. * @param __n2 The number of characters to compare. * @return Integer < 0, 0, or > 0. */ - template <typename _Tp> - _If_sv<_Tp, int> - compare(size_type __pos1, size_type __n1, const _Tp& __svt, - size_type __pos2, size_type __n2 = npos) const - { - __sv_type __sv = __svt; - return __sv_type(*this) - .substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2)); - } + template <typename _Tp> + _If_sv<_Tp, int> + compare(size_type __pos1, size_type __n1, const _Tp& __svt, + size_type __pos2, size_type __n2 = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return __sv_type(*this) + .substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2)); + } #endif // C++17 /** @@ -3348,6 +3440,22 @@ __and_<is_convertible<const _Tp&, __sv_type>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; + + // Allows an implicit conversion to __sv_type. + static __sv_type _S_to_string_view(__sv_type __svt) noexcept + { + return __svt; + } + + // Wraps a string_view by explicit conversion and thus + // allows to add an internal constructor that does not + // participate in overload resolution when a string_view + // is provided. + struct __sv_wrapper + { + explicit __sv_wrapper(__sv_type __sv) noexcept : _M_sv(__sv) {} + __sv_type _M_sv; + }; #endif public: @@ -3474,24 +3582,35 @@ #if __cplusplus > 201402L /** * @brief Construct string from a substring of a string_view. - * @param __t Source string view. + * @param __t Source object convertible to string view. * @param __pos The index of the first character to copy from __t. * @param __n The number of characters to copy from __t. * @param __a Allocator to use. */ - template<typename _Tp, typename = _If_sv<_Tp, void>> - basic_string(const _Tp& __t, size_type __pos, size_type __n, + template<typename _Tp, typename = _If_sv<_Tp, void>> + basic_string(const _Tp& __t, size_type __pos, size_type __n, const _Alloc& __a = _Alloc()) - : basic_string(__sv_type(__t).substr(__pos, __n), __a) { } - + : basic_string(_S_to_string_view(__t).substr(__pos, __n), __a) { } + /** * @brief Construct string from a string_view. - * @param __sv Source string view. + * @param __t Source object convertible to string view. * @param __a Allocator to use (default is default allocator). */ + template<typename _Tp, typename = _If_sv<_Tp, void>> explicit - basic_string(__sv_type __sv, const _Alloc& __a = _Alloc()) - : basic_string(__sv.data(), __sv.size(), __a) { } + basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) + : basic_string(__sv_wrapper(_S_to_string_view(__t)), __a) { } + + /** + * @brief Only internally used: Construct string from a string view + * wrapper. + * @param __svw string view wrapper. + * @param __a Allocator to use. + */ + explicit + basic_string(__sv_wrapper __svw, const _Alloc& __a) + : basic_string(__svw._M_sv.data(), __svw._M_sv.size(), __a) { } #endif // C++17 /** @@ -3562,12 +3681,12 @@ #if __cplusplus > 201402L /** * @brief Set value to string constructed from a string_view. - * @param __sv A string_view. + * @param __svt An object convertible to string_view. */ - template<typename _Tp> - _If_sv<_Tp, basic_string&> - operator=(_Tp __sv) - { return this->assign(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator=(const _Tp& __svt) + { return this->assign(__svt); } /** * @brief Convert to a string_view. @@ -3984,12 +4103,13 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt The object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - operator+=(__sv_type __sv) - { return this->append(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator+=(const _Tp& __svt) + { return this->append(__svt); } #endif // C++17 /** @@ -4075,29 +4195,34 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt The object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - append(__sv_type __sv) - { return this->append(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->append(__sv.data(), __sv.size()); + } /** * @brief Append a range of characters from a string_view. - * @param __sv The string_view to be appended from. + * @param __svt The object convertible to string_view to be appended + * from. * @param __pos The position in the string_view to append from. * @param __n The number of characters to append from the string_view. * @return Reference to this string. */ template <typename _Tp> - _If_sv<_Tp, basic_string&> - append(const _Tp& __svt, size_type __pos, size_type __n = npos) - { - __sv_type __sv = __svt; - return append(__sv.data() - + __sv._M_check(__pos, "basic_string::append"), - __sv._M_limit(__pos, __n)); - } + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt, size_type __pos, size_type __n = npos) + { + __sv_type __sv = __svt; + return append(__sv.data() + + __sv._M_check(__pos, "basic_string::append"), + __sv._M_limit(__pos, __n)); + } #endif // C++17 /** @@ -4228,29 +4353,33 @@ #if __cplusplus > 201402L /** * @brief Set value from a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @return Reference to this string. */ - basic_string& - assign(__sv_type __sv) - { return this->assign(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->assign(__sv.data(), __sv.size()); + } /** * @brief Set value from a range of characters in a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @param __pos The position in the string_view to assign from. * @param __n The number of characters to assign. * @return Reference to this string. */ template <typename _Tp> - _If_sv<_Tp, basic_string&> - assign(const _Tp& __svt, size_type __pos, size_type __n = npos) - { - __sv_type __sv = __svt; - return assign(__sv.data() - + __sv._M_check(__pos, "basic_string::assign"), - __sv._M_limit(__pos, __n)); - } + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt, size_type __pos, size_type __n = npos) + { + __sv_type __sv = __svt; + return assign(__sv.data() + + __sv._M_check(__pos, "basic_string::assign"), + __sv._M_limit(__pos, __n)); + } #endif // C++17 /** @@ -4432,17 +4561,21 @@ /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - insert(size_type __pos, __sv_type __sv) - { return this->insert(__pos, __sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + insert(size_type __pos, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->insert(__pos, __sv.data(), __sv.size()); + } /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos Iterator referencing position in string_view to insert * from. * @param __n The number of characters to insert. @@ -4449,15 +4582,15 @@ * @return Reference to this string. */ template <typename _Tp> - _If_sv<_Tp, basic_string&> - insert(size_type __pos1, const _Tp& __svt, - size_type __pos2, size_type __n = npos) - { - __sv_type __sv = __svt; - return this->replace(__pos1, size_type(0), __sv.data() - + __sv._M_check(__pos2, "basic_string::insert"), - __sv._M_limit(__pos2, __n)); - } + _If_sv<_Tp, basic_string&> + insert(size_type __pos1, const _Tp& __svt, + size_type __pos2, size_type __n = npos) + { + __sv_type __sv = __svt; + return this->replace(__pos1, size_type(0), __sv.data() + + __sv._M_check(__pos2, "basic_string::insert"), + __sv._M_limit(__pos2, __n)); + } #endif // C++17 /** @@ -4819,32 +4952,36 @@ * @brief Replace range of characters with string_view. * @param __pos The position to replace at. * @param __n The number of characters to replace. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - replace(size_type __pos, size_type __n, __sv_type __sv) - { return this->replace(__pos, __n, __sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + replace(size_type __pos, size_type __n, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__pos, __n, __sv.data(), __sv.size()); + } /** * @brief Replace range of characters with string_view. * @param __pos1 The position to replace at. * @param __n1 The number of characters to replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos2 The position in the string_view to insert from. * @param __n2 The number of characters to insert. * @return Reference to this string. */ template <typename _Tp> - _If_sv<_Tp, basic_string&> - replace(size_type __pos1, size_type __n1, const _Tp& __svt, - size_type __pos2, size_type __n2 = npos) - { - __sv_type __sv = __svt; - return this->replace(__pos1, __n1, __sv.data() - + __sv._M_check(__pos2, "basic_string::replace"), - __sv._M_limit(__pos2, __n2)); - } + _If_sv<_Tp, basic_string&> + replace(size_type __pos1, size_type __n1, const _Tp& __svt, + size_type __pos2, size_type __n2 = npos) + { + __sv_type __sv = __svt; + return this->replace(__pos1, __n1, __sv.data() + + __sv._M_check(__pos2, "basic_string::replace"), + __sv._M_limit(__pos2, __n2)); + } /** * @brief Replace range of characters with string_view. @@ -4852,12 +4989,16 @@ to replace at. * @param __i2 An iterator referencing the end position for the replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @return Reference to this string. */ - basic_string& - replace(const_iterator __i1, const_iterator __i2, __sv_type __sv) - { return this->replace(__i1 - begin(), __i2 - __i1, __sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + replace(const_iterator __i1, const_iterator __i2, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__i1 - begin(), __i2 - __i1, __sv); + } #endif // C++17 private: @@ -5062,13 +5203,18 @@ #if __cplusplus > 201402L /** * @brief Find position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search from (default 0). * @return Index of start of first occurrence. */ - size_type - find(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5135,13 +5281,18 @@ #if __cplusplus > 201402L /** * @brief Find last position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search back from (default end). * @return Index of start of last occurrence. */ - size_type - rfind(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->rfind(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + rfind(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->rfind(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5213,13 +5364,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character of a string_view. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_first_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5291,13 +5448,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character of string. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_last_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5366,13 +5529,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt An object convertible to string_view containing + * characters to avoid. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_not_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_not_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_first_not_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5442,13 +5611,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt An object convertible to string_view containing + * characters to avoid. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_not_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_not_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_last_not_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5498,12 +5673,14 @@ #if __cplusplus > 201402L /** * @brief Compare to a string_view. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare against. * @return Integer < 0, 0, or > 0. */ - int - compare(__sv_type __sv) const + template<typename _Tp> + _If_sv<_Tp, int> + compare(const _Tp& __svt) const noexcept(is_same<_Tp, __sv_type>::value) { + __sv_type __sv = __svt; const size_type __size = this->size(); const size_type __osize = __sv.size(); const size_type __len = std::min(__size, __osize); @@ -5518,31 +5695,39 @@ * @brief Compare to a string_view. * @param __pos A position in the string to start comparing from. * @param __n The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @return Integer < 0, 0, or > 0. */ - int - compare(size_type __pos, size_type __n, __sv_type __sv) const - { return __sv_type(*this).substr(__pos, __n).compare(__sv); } + template<typename _Tp> + _If_sv<_Tp, int> + compare(size_type __pos, size_type __n, const _Tp& __svt) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return __sv_type(*this).substr(__pos, __n).compare(__sv); + } /** * @brief Compare to a string_view. * @param __pos1 A position in the string to start comparing from. * @param __n1 The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @param __pos2 A position in the string_view to start comparing from. * @param __n2 The number of characters to compare. * @return Integer < 0, 0, or > 0. */ - template <typename _Tp> - _If_sv<_Tp, int> - compare(size_type __pos1, size_type __n1, const _Tp& __svt, - size_type __pos2, size_type __n2 = npos) const - { - __sv_type __sv = __svt; - return __sv_type(*this) - .substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2)); - } + template <typename _Tp> + _If_sv<_Tp, int> + compare(size_type __pos1, size_type __n1, const _Tp& __svt, + size_type __pos2, size_type __n2 = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return __sv_type(*this) + .substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2)); + } #endif // C++17 /** Index: libstdc++-v3/testsuite/21_strings/basic_string/79162.cc =================================================================== --- libstdc++-v3/testsuite/21_strings/basic_string/79162.cc (nonexistent) +++ libstdc++-v3/testsuite/21_strings/basic_string/79162.cc (working copy) @@ -0,0 +1,37 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <string> + +template <class DataType> +class opt : public DataType +{ + opt(const opt &) = delete; + opt &operator=(const opt &) = delete; +public: + opt() {} +}; + +int main() +{ + opt<std::string> PGOTestProfileFile; + std::string ProfileFileName; + ProfileFileName = PGOTestProfileFile; +} Index: libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc =================================================================== --- libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc (nonexistent) +++ libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc (working copy) @@ -0,0 +1,41 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <string> + +int main() +{ + std::string s({"abc", 1}); + s = {"abc", 1}; + s += {"abc", 1}; + s.append({"abc", 1}); + s.assign({"abc", 1}); + s.insert(0, {"abc", 1}); + s.replace(0, 1, {"abc", 1}); + s.replace(s.cbegin(), s.cbegin(), {"abc", 1}); + s.find({"abc", 1}); + s.rfind({"abc", 1}); + s.find_first_of({"abc", 1}); + s.find_last_of({"abc", 1}); + s.find_first_not_of({"abc", 1}); + s.find_last_not_of({"abc", 1}); + s.compare({"abc", 1}); + s.compare(0, 1, {"abc", 1}); +} ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-07-30 13:01 ` Daniel Krügler @ 2017-08-18 18:27 ` Daniel Krügler 2017-09-04 15:48 ` Jonathan Wakely 1 sibling, 0 replies; 12+ messages in thread From: Daniel Krügler @ 2017-08-18 18:27 UTC (permalink / raw) To: Tim Song; +Cc: libstdc++, gcc-patches Hi, This is a friendly reminder asking for a review of the suggested patch! Thanks, - Daniel 2017-07-30 15:01 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: > 2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >> 2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>> 2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>> On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>> <daniel.kruegler@gmail.com> wrote: >>>>> + // Performs an implicit conversion from _Tp to __sv_type. >>>>> + template<typename _Tp> >>>>> + static __sv_type _S_to_string_view(const _Tp& __svt) >>>>> + { >>>>> + return __svt; >>>>> + } >>>> >>>> I might have gone for >>>> >>>> + static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>> + { >>>> + return __svt; >>>> + } >>>> >>>> With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>> for the absence of is_nothrow_convertible (basically the same thing I >>>> did in LWG 2993's PR). >>> >>> Agreed, that makes very much sense. I will adjust the P/R, but before >>> I resubmit I would like to get feedback whether the other two compare >>> functions also should become conditionally noexcept. >> >> Locally I have now performed the sole change of the _S_to_string_view >> declaration getting rid of the template, but would also like to gather >> feedback from the maintainers whether I should also change the form of >> the conditional noexcept to use the expression >> >> noexcept(_S_to_string_view(__t)) >> >> instead of the current >> >> is_same<_Tp, __sv_type>::value >> >> as suggested by Tim Song. >> >> I'm asking also, because I have a paper proposing to standardize >> is_nothrow_convertible submitted for the upcoming C++ mailing - This >> would be one of the first applications in the library ;-) > > A slightly revised patch update: It replaces the _S_to_string_view > template by a simpler _S_to_string_view function as of Tim Song's > suggestion, but still uses the simplified noexcept specification > deferring it to a future application case for is_nothrow_convertible. > Furthermore now all three compare function templates are now > (conditionally) noexcept by an (off-list) suggestion from Jonathan > Wakely. > > Thanks, > > - Daniel -- ________________________________ SavedURI :Show URLShow URLSavedURI : SavedURI :Hide URLHide URLSavedURI : https://mail.google.com/_/scs/mail-static/_/js/k=gmail.main.de.LEt2fN4ilLE.O/m=m_i,t,it/am=OCMOBiHj9kJxhnelj6j997_NLil29vVAOBGeBBRgJwD-m_0_8B_AD-qOEw/rt=h/d=1/rs=AItRSTODy9wv1JKZMABIG3Ak8ViC4kuOWA?random=1395770800154https://mail.google.com/_/scs/mail-static/_/js/k=gmail.main.de.LEt2fN4ilLE.O/m=m_i,t,it/am=OCMOBiHj9kJxhnelj6j997_NLil29vVAOBGeBBRgJwD-m_0_8B_AD-qOEw/rt=h/d=1/rs=AItRSTODy9wv1JKZMABIG3Ak8ViC4kuOWA?random=1395770800154 ________________________________ ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-07-30 13:01 ` Daniel Krügler 2017-08-18 18:27 ` Daniel Krügler @ 2017-09-04 15:48 ` Jonathan Wakely 2017-09-11 16:55 ` Jonathan Wakely 2017-09-20 15:36 ` Jonathan Wakely 1 sibling, 2 replies; 12+ messages in thread From: Jonathan Wakely @ 2017-09-04 15:48 UTC (permalink / raw) To: Daniel Krügler; +Cc: Tim Song, libstdc++, gcc-patches On 30/07/17 15:01 +0200, Daniel Krügler wrote: >2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >> 2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>> 2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>> On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>> <daniel.kruegler@gmail.com> wrote: >>>>> + // Performs an implicit conversion from _Tp to __sv_type. >>>>> + template<typename _Tp> >>>>> + static __sv_type _S_to_string_view(const _Tp& __svt) >>>>> + { >>>>> + return __svt; >>>>> + } >>>> >>>> I might have gone for >>>> >>>> + static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>> + { >>>> + return __svt; >>>> + } >>>> >>>> With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>> for the absence of is_nothrow_convertible (basically the same thing I >>>> did in LWG 2993's PR). >>> >>> Agreed, that makes very much sense. I will adjust the P/R, but before >>> I resubmit I would like to get feedback whether the other two compare >>> functions also should become conditionally noexcept. >> >> Locally I have now performed the sole change of the _S_to_string_view >> declaration getting rid of the template, but would also like to gather >> feedback from the maintainers whether I should also change the form of >> the conditional noexcept to use the expression >> >> noexcept(_S_to_string_view(__t)) >> >> instead of the current >> >> is_same<_Tp, __sv_type>::value >> >> as suggested by Tim Song. >> >> I'm asking also, because I have a paper proposing to standardize >> is_nothrow_convertible submitted for the upcoming C++ mailing - This >> would be one of the first applications in the library ;-) > >A slightly revised patch update: It replaces the _S_to_string_view >template by a simpler _S_to_string_view function as of Tim Song's >suggestion, but still uses the simplified noexcept specification >deferring it to a future application case for is_nothrow_convertible. >Furthermore now all three compare function templates are now >(conditionally) noexcept by an (off-list) suggestion from Jonathan >Wakely. I've committed this, after some whitespace fixes and testing. Thanks! ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-09-04 15:48 ` Jonathan Wakely @ 2017-09-11 16:55 ` Jonathan Wakely 2017-09-20 15:36 ` Jonathan Wakely 1 sibling, 0 replies; 12+ messages in thread From: Jonathan Wakely @ 2017-09-11 16:55 UTC (permalink / raw) To: Daniel Krügler; +Cc: Tim Song, libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 2577 bytes --] On 04/09/17 16:48 +0100, Jonathan Wakely wrote: >On 30/07/17 15:01 +0200, Daniel Krügler wrote: >>2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>>>On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>>><daniel.kruegler@gmail.com> wrote: >>>>>>+ // Performs an implicit conversion from _Tp to __sv_type. >>>>>>+ template<typename _Tp> >>>>>>+ static __sv_type _S_to_string_view(const _Tp& __svt) >>>>>>+ { >>>>>>+ return __svt; >>>>>>+ } >>>>> >>>>>I might have gone for >>>>> >>>>>+ static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>>>+ { >>>>>+ return __svt; >>>>>+ } >>>>> >>>>>With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>>>for the absence of is_nothrow_convertible (basically the same thing I >>>>>did in LWG 2993's PR). >>>> >>>>Agreed, that makes very much sense. I will adjust the P/R, but before >>>>I resubmit I would like to get feedback whether the other two compare >>>>functions also should become conditionally noexcept. >>> >>>Locally I have now performed the sole change of the _S_to_string_view >>>declaration getting rid of the template, but would also like to gather >>>feedback from the maintainers whether I should also change the form of >>>the conditional noexcept to use the expression >>> >>>noexcept(_S_to_string_view(__t)) >>> >>>instead of the current >>> >>>is_same<_Tp, __sv_type>::value >>> >>>as suggested by Tim Song. >>> >>>I'm asking also, because I have a paper proposing to standardize >>>is_nothrow_convertible submitted for the upcoming C++ mailing - This >>>would be one of the first applications in the library ;-) >> >>A slightly revised patch update: It replaces the _S_to_string_view >>template by a simpler _S_to_string_view function as of Tim Song's >>suggestion, but still uses the simplified noexcept specification >>deferring it to a future application case for is_nothrow_convertible. >>Furthermore now all three compare function templates are now >>(conditionally) noexcept by an (off-list) suggestion from Jonathan >>Wakely. > >I've committed this, after some whitespace fixes and testing. > >Thanks! We also need this tweak, to account for the fact that the old std::string has this signature: basic_string& replace(iterator __i1, iterator __i2, initializer_list<_CharT> __l) Tested powerpc64le-linux, committed to trunk. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 895 bytes --] commit c435fd7ed919ae54fc8f730844c7466822787ff8 Author: Jonathan Wakely <jwakely@redhat.com> Date: Mon Sep 11 17:29:34 2017 +0100 Adjust test to pass with old std::string * testsuite/21_strings/basic_string/lwg2946.cc: Adjust for compatibility with old COW std::string. diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc b/libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc index 74d5a5c89a7..fe1f15553fb 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/lwg2946.cc @@ -29,7 +29,7 @@ int main() s.assign({"abc", 1}); s.insert(0, {"abc", 1}); s.replace(0, 1, {"abc", 1}); - s.replace(s.cbegin(), s.cbegin(), {"abc", 1}); + s.replace(s.begin(), s.begin(), {"abc", 1}); s.find({"abc", 1}); s.rfind({"abc", 1}); s.find_first_of({"abc", 1}); ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-09-04 15:48 ` Jonathan Wakely 2017-09-11 16:55 ` Jonathan Wakely @ 2017-09-20 15:36 ` Jonathan Wakely 2017-09-20 16:52 ` Jonathan Wakely 1 sibling, 1 reply; 12+ messages in thread From: Jonathan Wakely @ 2017-09-20 15:36 UTC (permalink / raw) To: Daniel Krügler; +Cc: Tim Song, libstdc++, gcc-patches On 04/09/17 16:48 +0100, Jonathan Wakely wrote: >On 30/07/17 15:01 +0200, Daniel Krügler wrote: >>2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>>>On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>>><daniel.kruegler@gmail.com> wrote: >>>>>>+ // Performs an implicit conversion from _Tp to __sv_type. >>>>>>+ template<typename _Tp> >>>>>>+ static __sv_type _S_to_string_view(const _Tp& __svt) >>>>>>+ { >>>>>>+ return __svt; >>>>>>+ } >>>>> >>>>>I might have gone for >>>>> >>>>>+ static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>>>+ { >>>>>+ return __svt; >>>>>+ } >>>>> >>>>>With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>>>for the absence of is_nothrow_convertible (basically the same thing I >>>>>did in LWG 2993's PR). >>>> >>>>Agreed, that makes very much sense. I will adjust the P/R, but before >>>>I resubmit I would like to get feedback whether the other two compare >>>>functions also should become conditionally noexcept. >>> >>>Locally I have now performed the sole change of the _S_to_string_view >>>declaration getting rid of the template, but would also like to gather >>>feedback from the maintainers whether I should also change the form of >>>the conditional noexcept to use the expression >>> >>>noexcept(_S_to_string_view(__t)) >>> >>>instead of the current >>> >>>is_same<_Tp, __sv_type>::value >>> >>>as suggested by Tim Song. >>> >>>I'm asking also, because I have a paper proposing to standardize >>>is_nothrow_convertible submitted for the upcoming C++ mailing - This >>>would be one of the first applications in the library ;-) >> >>A slightly revised patch update: It replaces the _S_to_string_view >>template by a simpler _S_to_string_view function as of Tim Song's >>suggestion, but still uses the simplified noexcept specification >>deferring it to a future application case for is_nothrow_convertible. >>Furthermore now all three compare function templates are now >>(conditionally) noexcept by an (off-list) suggestion from Jonathan >>Wakely. > >I've committed this, after some whitespace fixes and testing. > >Thanks! This change causes two regressions in C++17 mode, see https://gcc.gnu.org/ml/gcc-testresults/2017-09/msg01674.html FAIL: 21_strings/basic_string/cons/char/moveable2.cc execution test FAIL: 21_strings/basic_string/cons/wchar_t/moveable2.cc execution test Here's a reduced version of that test, which passes in C++14 and fails in C++17: #include <string> #include <assert.h> class tstring : public std::string { public: tstring() : std::string() {} tstring(tstring&& s) : std::string(std::move(s)) {} }; int main() { tstring b; b.push_back('1'); tstring c(std::move(b)); assert( c.size() == 1 && c[0] == '1' ); assert( b.size() == 0 ); } The second assertion fails, because this mem-initializer: tstring(tstring&& s) : std::string(std::move(s)) {} now prefers to use the new constructor: basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) because tstring is convertible to string_view. This turns a non-allocating move into an allocating copy. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-09-20 15:36 ` Jonathan Wakely @ 2017-09-20 16:52 ` Jonathan Wakely 2017-09-20 18:00 ` Jonathan Wakely 0 siblings, 1 reply; 12+ messages in thread From: Jonathan Wakely @ 2017-09-20 16:52 UTC (permalink / raw) To: Daniel Krügler; +Cc: Tim Song, libstdc++, gcc-patches On 20/09/17 16:36 +0100, Jonathan Wakely wrote: >On 04/09/17 16:48 +0100, Jonathan Wakely wrote: >>On 30/07/17 15:01 +0200, Daniel Krügler wrote: >>>2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>>2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>>>>On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>>>><daniel.kruegler@gmail.com> wrote: >>>>>>>+ // Performs an implicit conversion from _Tp to __sv_type. >>>>>>>+ template<typename _Tp> >>>>>>>+ static __sv_type _S_to_string_view(const _Tp& __svt) >>>>>>>+ { >>>>>>>+ return __svt; >>>>>>>+ } >>>>>> >>>>>>I might have gone for >>>>>> >>>>>>+ static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>>>>+ { >>>>>>+ return __svt; >>>>>>+ } >>>>>> >>>>>>With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>>>>for the absence of is_nothrow_convertible (basically the same thing I >>>>>>did in LWG 2993's PR). >>>>> >>>>>Agreed, that makes very much sense. I will adjust the P/R, but before >>>>>I resubmit I would like to get feedback whether the other two compare >>>>>functions also should become conditionally noexcept. >>>> >>>>Locally I have now performed the sole change of the _S_to_string_view >>>>declaration getting rid of the template, but would also like to gather >>>>feedback from the maintainers whether I should also change the form of >>>>the conditional noexcept to use the expression >>>> >>>>noexcept(_S_to_string_view(__t)) >>>> >>>>instead of the current >>>> >>>>is_same<_Tp, __sv_type>::value >>>> >>>>as suggested by Tim Song. >>>> >>>>I'm asking also, because I have a paper proposing to standardize >>>>is_nothrow_convertible submitted for the upcoming C++ mailing - This >>>>would be one of the first applications in the library ;-) >>> >>>A slightly revised patch update: It replaces the _S_to_string_view >>>template by a simpler _S_to_string_view function as of Tim Song's >>>suggestion, but still uses the simplified noexcept specification >>>deferring it to a future application case for is_nothrow_convertible. >>>Furthermore now all three compare function templates are now >>>(conditionally) noexcept by an (off-list) suggestion from Jonathan >>>Wakely. >> >>I've committed this, after some whitespace fixes and testing. >> >>Thanks! > >This change causes two regressions in C++17 mode, see >https://gcc.gnu.org/ml/gcc-testresults/2017-09/msg01674.html > >FAIL: 21_strings/basic_string/cons/char/moveable2.cc execution test >FAIL: 21_strings/basic_string/cons/wchar_t/moveable2.cc execution test > >Here's a reduced version of that test, which passes in C++14 and fails >in C++17: > >#include <string> >#include <assert.h> > >class tstring : public std::string >{ >public: > tstring() : std::string() {} > tstring(tstring&& s) : std::string(std::move(s)) {} >}; > >int main() >{ > tstring b; > b.push_back('1'); > tstring c(std::move(b)); > assert( c.size() == 1 && c[0] == '1' ); > assert( b.size() == 0 ); >} > >The second assertion fails, because this mem-initializer: > > tstring(tstring&& s) : std::string(std::move(s)) {} > >now prefers to use the new constructor: > > basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) > >because tstring is convertible to string_view. > >This turns a non-allocating move into an allocating copy. This patch fixes the failure above, I'm testing it now. --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -115,6 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template<typename _Tp, typename _Res> using _If_sv = enable_if_t< __and_<is_convertible<const _Tp&, __sv_type>, + __not_<is_convertible<const _Tp*, const basic_string*>>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-09-20 16:52 ` Jonathan Wakely @ 2017-09-20 18:00 ` Jonathan Wakely 2017-09-20 22:03 ` Jonathan Wakely 0 siblings, 1 reply; 12+ messages in thread From: Jonathan Wakely @ 2017-09-20 18:00 UTC (permalink / raw) To: Daniel Krügler; +Cc: Tim Song, libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 4334 bytes --] On 20/09/17 17:52 +0100, Jonathan Wakely wrote: >On 20/09/17 16:36 +0100, Jonathan Wakely wrote: >>On 04/09/17 16:48 +0100, Jonathan Wakely wrote: >>>On 30/07/17 15:01 +0200, Daniel Krügler wrote: >>>>2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>>2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>>>2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>>>>>On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>>>>><daniel.kruegler@gmail.com> wrote: >>>>>>>>+ // Performs an implicit conversion from _Tp to __sv_type. >>>>>>>>+ template<typename _Tp> >>>>>>>>+ static __sv_type _S_to_string_view(const _Tp& __svt) >>>>>>>>+ { >>>>>>>>+ return __svt; >>>>>>>>+ } >>>>>>> >>>>>>>I might have gone for >>>>>>> >>>>>>>+ static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>>>>>+ { >>>>>>>+ return __svt; >>>>>>>+ } >>>>>>> >>>>>>>With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>>>>>for the absence of is_nothrow_convertible (basically the same thing I >>>>>>>did in LWG 2993's PR). >>>>>> >>>>>>Agreed, that makes very much sense. I will adjust the P/R, but before >>>>>>I resubmit I would like to get feedback whether the other two compare >>>>>>functions also should become conditionally noexcept. >>>>> >>>>>Locally I have now performed the sole change of the _S_to_string_view >>>>>declaration getting rid of the template, but would also like to gather >>>>>feedback from the maintainers whether I should also change the form of >>>>>the conditional noexcept to use the expression >>>>> >>>>>noexcept(_S_to_string_view(__t)) >>>>> >>>>>instead of the current >>>>> >>>>>is_same<_Tp, __sv_type>::value >>>>> >>>>>as suggested by Tim Song. >>>>> >>>>>I'm asking also, because I have a paper proposing to standardize >>>>>is_nothrow_convertible submitted for the upcoming C++ mailing - This >>>>>would be one of the first applications in the library ;-) >>>> >>>>A slightly revised patch update: It replaces the _S_to_string_view >>>>template by a simpler _S_to_string_view function as of Tim Song's >>>>suggestion, but still uses the simplified noexcept specification >>>>deferring it to a future application case for is_nothrow_convertible. >>>>Furthermore now all three compare function templates are now >>>>(conditionally) noexcept by an (off-list) suggestion from Jonathan >>>>Wakely. >>> >>>I've committed this, after some whitespace fixes and testing. >>> >>>Thanks! >> >>This change causes two regressions in C++17 mode, see >>https://gcc.gnu.org/ml/gcc-testresults/2017-09/msg01674.html >> >>FAIL: 21_strings/basic_string/cons/char/moveable2.cc execution test >>FAIL: 21_strings/basic_string/cons/wchar_t/moveable2.cc execution test >> >>Here's a reduced version of that test, which passes in C++14 and fails >>in C++17: >> >>#include <string> >>#include <assert.h> >> >>class tstring : public std::string >>{ >>public: >>tstring() : std::string() {} >>tstring(tstring&& s) : std::string(std::move(s)) {} >>}; >> >>int main() >>{ >>tstring b; >>b.push_back('1'); >>tstring c(std::move(b)); >>assert( c.size() == 1 && c[0] == '1' ); >>assert( b.size() == 0 ); >>} >> >>The second assertion fails, because this mem-initializer: >> >>tstring(tstring&& s) : std::string(std::move(s)) {} >> >>now prefers to use the new constructor: >> >>basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) >> >>because tstring is convertible to string_view. >> >>This turns a non-allocating move into an allocating copy. > >This patch fixes the failure above, I'm testing it now. > >--- a/libstdc++-v3/include/bits/basic_string.h >+++ b/libstdc++-v3/include/bits/basic_string.h >@@ -115,6 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > template<typename _Tp, typename _Res> > using _If_sv = enable_if_t< > __and_<is_convertible<const _Tp&, __sv_type>, >+ __not_<is_convertible<const _Tp*, const basic_string*>>, > __not_<is_convertible<const _Tp&, const _CharT*>>>::value, > _Res>; > > I'm committing this to fix the regression. If the final LWG 2946 resolution does something different we can change it again. Tested powerpc64le-linux, committed to trunk. I'll start another test run with all variations ... [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 5025 bytes --] commit 45143c77f09ff9ebe27761bca81ccd4f9f928d9b Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Sep 20 17:56:53 2017 +0100 PR libstdc++/79162 Fix std::string regression due to LWG 2946 PR libstdc++/79162 * include/bits/basic_string.h (basic_string::_If_sv): Remove from the overload set when the argument is derived from basic_string. * testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc: New test. * testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc: New test. diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 0ef139b2c2b..8a382d5640c 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -115,6 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template<typename _Tp, typename _Res> using _If_sv = enable_if_t< __and_<is_convertible<const _Tp&, __sv_type>, + __not_<is_convertible<const _Tp*, const basic_string*>>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc new file mode 100644 index 00000000000..88be60d05ab --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc @@ -0,0 +1,53 @@ +// { dg-options "-std=gnu++17" } +// { dg-do run { target c++17 } } + +// Copyright (C) 2011-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// NOTE: This makes use of the fact that we know how moveable +// is implemented on string (via swap). If the implementation changed +// this test may begin to fail. + +#include <string> +#include <utility> +#include <testsuite_hooks.h> + +class tstring : public std::basic_string<char> +{ +public: + tstring() : std::basic_string<char>() {} + tstring(tstring&& s) : std::basic_string<char>(std::move(s)) {} + tstring& operator=(tstring&& s) = default; +}; + +void test01() +{ + tstring a, b; + a.push_back('1'); + b = std::move(a); + VERIFY( b.size() == 1 && b[0] == '1' && a.size() == 0 ); + + tstring c(std::move(b)); + VERIFY( c.size() == 1 && c[0] == '1' ); + VERIFY( b.size() == 0 ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc new file mode 100644 index 00000000000..63684de68a6 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc @@ -0,0 +1,53 @@ +// { dg-options "-std=gnu++17" } +// { dg-do run { target c++17 } } + +// Copyright (C) 2011-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// NOTE: This makes use of the fact that we know how moveable +// is implemented on string (via swap). If the implementation changed +// this test may begin to fail. + +#include <string> +#include <utility> +#include <testsuite_hooks.h> + +class tstring : public std::basic_string<wchar_t> +{ +public: + tstring() : std::basic_string<wchar_t>() {} + tstring(tstring&& s) : std::basic_string<wchar_t>(std::move(s)) {} + tstring& operator=(tstring&& s) = default; +}; + +void test01() +{ + tstring a, b; + a.push_back(L'1'); + b = std::move(a); + VERIFY( b.size() == 1 && b[0] == L'1' && a.size() == 0 ); + + tstring c(std::move(b)); + VERIFY( c.size() == 1 && c[0] == L'1' ); + VERIFY( b.size() == 0 ); +} + +int main() +{ + test01(); + return 0; +} ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) 2017-09-20 18:00 ` Jonathan Wakely @ 2017-09-20 22:03 ` Jonathan Wakely 0 siblings, 0 replies; 12+ messages in thread From: Jonathan Wakely @ 2017-09-20 22:03 UTC (permalink / raw) To: Daniel Krügler; +Cc: Tim Song, libstdc++, gcc-patches [-- Attachment #1: Type: text/plain, Size: 4605 bytes --] On 20/09/17 18:59 +0100, Jonathan Wakely wrote: >On 20/09/17 17:52 +0100, Jonathan Wakely wrote: >>On 20/09/17 16:36 +0100, Jonathan Wakely wrote: >>>On 04/09/17 16:48 +0100, Jonathan Wakely wrote: >>>>On 30/07/17 15:01 +0200, Daniel Krügler wrote: >>>>>2017-07-28 22:40 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>>>2017-07-28 22:29 GMT+02:00 Daniel Krügler <daniel.kruegler@gmail.com>: >>>>>>>2017-07-28 22:25 GMT+02:00 Tim Song <t.canens.cpp@gmail.com>: >>>>>>>>On Fri, Jul 28, 2017 at 4:10 PM, Daniel Krügler >>>>>>>><daniel.kruegler@gmail.com> wrote: >>>>>>>>>+ // Performs an implicit conversion from _Tp to __sv_type. >>>>>>>>>+ template<typename _Tp> >>>>>>>>>+ static __sv_type _S_to_string_view(const _Tp& __svt) >>>>>>>>>+ { >>>>>>>>>+ return __svt; >>>>>>>>>+ } >>>>>>>> >>>>>>>>I might have gone for >>>>>>>> >>>>>>>>+ static __sv_type _S_to_string_view(__sv_type __svt) noexcept >>>>>>>>+ { >>>>>>>>+ return __svt; >>>>>>>>+ } >>>>>>>> >>>>>>>>With that, we can also use noexcept(_S_to_string_view(__t)) to make up >>>>>>>>for the absence of is_nothrow_convertible (basically the same thing I >>>>>>>>did in LWG 2993's PR). >>>>>>> >>>>>>>Agreed, that makes very much sense. I will adjust the P/R, but before >>>>>>>I resubmit I would like to get feedback whether the other two compare >>>>>>>functions also should become conditionally noexcept. >>>>>> >>>>>>Locally I have now performed the sole change of the _S_to_string_view >>>>>>declaration getting rid of the template, but would also like to gather >>>>>>feedback from the maintainers whether I should also change the form of >>>>>>the conditional noexcept to use the expression >>>>>> >>>>>>noexcept(_S_to_string_view(__t)) >>>>>> >>>>>>instead of the current >>>>>> >>>>>>is_same<_Tp, __sv_type>::value >>>>>> >>>>>>as suggested by Tim Song. >>>>>> >>>>>>I'm asking also, because I have a paper proposing to standardize >>>>>>is_nothrow_convertible submitted for the upcoming C++ mailing - This >>>>>>would be one of the first applications in the library ;-) >>>>> >>>>>A slightly revised patch update: It replaces the _S_to_string_view >>>>>template by a simpler _S_to_string_view function as of Tim Song's >>>>>suggestion, but still uses the simplified noexcept specification >>>>>deferring it to a future application case for is_nothrow_convertible. >>>>>Furthermore now all three compare function templates are now >>>>>(conditionally) noexcept by an (off-list) suggestion from Jonathan >>>>>Wakely. >>>> >>>>I've committed this, after some whitespace fixes and testing. >>>> >>>>Thanks! >>> >>>This change causes two regressions in C++17 mode, see >>>https://gcc.gnu.org/ml/gcc-testresults/2017-09/msg01674.html >>> >>>FAIL: 21_strings/basic_string/cons/char/moveable2.cc execution test >>>FAIL: 21_strings/basic_string/cons/wchar_t/moveable2.cc execution test >>> >>>Here's a reduced version of that test, which passes in C++14 and fails >>>in C++17: >>> >>>#include <string> >>>#include <assert.h> >>> >>>class tstring : public std::string >>>{ >>>public: >>>tstring() : std::string() {} >>>tstring(tstring&& s) : std::string(std::move(s)) {} >>>}; >>> >>>int main() >>>{ >>>tstring b; >>>b.push_back('1'); >>>tstring c(std::move(b)); >>>assert( c.size() == 1 && c[0] == '1' ); >>>assert( b.size() == 0 ); >>>} >>> >>>The second assertion fails, because this mem-initializer: >>> >>>tstring(tstring&& s) : std::string(std::move(s)) {} >>> >>>now prefers to use the new constructor: >>> >>>basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) >>> >>>because tstring is convertible to string_view. >>> >>>This turns a non-allocating move into an allocating copy. >> >>This patch fixes the failure above, I'm testing it now. >> >>--- a/libstdc++-v3/include/bits/basic_string.h >>+++ b/libstdc++-v3/include/bits/basic_string.h >>@@ -115,6 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 >> template<typename _Tp, typename _Res> >> using _If_sv = enable_if_t< >> __and_<is_convertible<const _Tp&, __sv_type>, >>+ __not_<is_convertible<const _Tp*, const basic_string*>>, >> __not_<is_convertible<const _Tp&, const _CharT*>>>::value, >> _Res>; >> >> > >I'm committing this to fix the regression. If the final LWG 2946 >resolution does something different we can change it again. > >Tested powerpc64le-linux, committed to trunk. > >I'll start another test run with all variations ... That test run revealed I forgot to make the same change to the _If_sv helper in the old std::basic_string. [-- Attachment #2: patch.txt --] [-- Type: text/x-patch, Size: 981 bytes --] commit ab3a6ce803de3d21325bb82978f1f6d61c5cb4e2 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Sep 20 22:48:04 2017 +0100 PR libstdc++/79162 Fix std::string regression due to LWG 2946 (old ABI) PR libstdc++/79162 * include/bits/basic_string.h [!_GLIBCXX_USE_CXX11_ABI] (basic_string::_If_sv): Remove from the overload set when the argument is derived from basic_string. diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 8a382d5640c..a4b81137571 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -3439,6 +3439,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 template<typename _Tp, typename _Res> using _If_sv = enable_if_t< __and_<is_convertible<const _Tp&, __sv_type>, + __not_<is_convertible<const _Tp*, const basic_string*>>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) @ 2017-07-28 20:07 Daniel Krügler 0 siblings, 0 replies; 12+ messages in thread From: Daniel Krügler @ 2017-07-28 20:07 UTC (permalink / raw) To: gcc-patches List, libstdc [-- Attachment #1: Type: text/plain, Size: 1865 bytes --] This patch attempts to solve an issue in basic_string after adding string_view to several functions that came in during incomplete patch of LWG 2758/LWG 2946, in short: Functions that take a string_view parameter value are now replaced by constrained templates taking const T& that is convertible to string_view. The patch also attempts to complete the LWG 2946 P/R. With the absence of the std::is_nothrow_convertible traits, the P/R also restores some of the lost noexcept specifications of const functions (find, compare, etc) by conditional noexcept simply comparing whether T is the same type as string_view. During that fix two related, minor problems where found and also fixed: a) Member int compare(basic_string_view<charT, traits> sv) const; should be noexcept according the spec, but this function wasn't at all. Since the changes for LWG 2946 required me to touch the noexcept specifier anyway I replaced it by the conditional noexcept mentioned above. I do not know what the general policy for "narrow contract" functions is in libstdc++ code, I therefore didn't touch the also missing (but optional) noexcept for int compare(size_type pos1, size_type n1,basic_string_view<charT, traits> sv) const; template<class T> int compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const; If wanted, I can apply the same conditional noexcept here as well. b) Two constructors using the const T& -> string_view conversion did this via explicit conversion instead of implicit conversion. This difference can be observed by user-code and in certain cases either a well-formed program can become ill-formed or may perform different runtime behaviour (Overloaded conversion operators, one explicit, the other implicit). This patch is *untested*, because I cannot make the tests run on my Windows system. Thanks, - Daniel [-- Attachment #2: ChangeLog_79162.patch --] [-- Type: application/octet-stream, Size: 2115 bytes --] Index: ChangeLog =================================================================== --- ChangeLog (revision 250685) +++ ChangeLog (working copy) @@ -1,3 +1,34 @@ +2017-07-28 Daniel Kruegler <daniel.kruegler@gmail.com> + + PR libstdc++/79162 + Implement LWG 2946, LWG 2758's resolution missed further corrections + * include/bits/basic_string.h (basic_string::compare): Added missing + required noexcept specification. + * include/bits/basic_string.h (basic_string): Introduce internal + _S_to_string_view and __sv_wrapper for implicit string_view conversion. + * include/bits/basic_string.h (basic_string::basic_string): Fix explicit + string_view conversion by implicit conversion using _S_to_string_view and + __sv_wrapper. + * include/bits/basic_string.h (basic_string): Introduce internal + basic_string(__sv_wrapper, Alloc) constructor. + * include/bits/basic_string.h (basic_string): Fix operator=(T) template + by operator=(const T&) template for uncopyable types (79162). + * include/bits/basic_string.h (basic_string::operator+=, + basic_string::append, basic_string::assign, basic_string::insert, + basic_string::replace, basic_string::find, basic_string::rfind, + basic_string::find_first_of, basic_string::find_last_of, + basic_string::find_first_not_of, basic_string::find_last_not_of, + basic_string::compare): Replace __sv_type argument by template const T& + (LWG 2946) and corrected documentation describing __sv_type argument. + * include/bits/basic_string.h (basic_string::find, basic_string::rfind, + basic_string::find_first_of, basic_string::find_last_of, + basic_string::find_first_not_of, basic_string::find_last_not_of, + basic_string::compare): Replace unconditional noexcept specification by + conditional noexcept specification to balance the remove of noexcept by + LWG 2946. + * testsuite/21_strings/basic_string/79162.cc: New. + * testsuite/21_strings/basic_string/lwg2946.cc: New. + 2017-07-26 Jonathan Wakely <jwakely@redhat.com> * testsuite/27_io/basic_fstream/53984.cc: Fix test. [-- Attachment #3: 79162.patch --] [-- Type: application/octet-stream, Size: 38505 bytes --] Index: include/bits/basic_string.h =================================================================== --- include/bits/basic_string.h (revision 250685) +++ include/bits/basic_string.h (working copy) @@ -117,6 +117,23 @@ __and_<is_convertible<const _Tp&, __sv_type>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; + + // Performs an implicit conversion from _Tp to __sv_type. + template<typename _Tp> + static __sv_type _S_to_string_view(const _Tp& __svt) + { + return __svt; + } + + // Wraps a string_view by explicit conversion and thus + // allows to add an internal constructor that does not + // participate in overload resolution when a string_view + // is provided. + struct __sv_wrapper + { + explicit __sv_wrapper(__sv_type __sv) noexcept : _M_sv(__sv) {} + __sv_type _M_sv; + }; #endif // Use empty-base optimization: http://www.cantrip.org/emptyopt.html @@ -593,7 +610,7 @@ #if __cplusplus > 201402L /** * @brief Construct string from a substring of a string_view. - * @param __t Source string view. + * @param __t Source object convertible to string view. * @param __pos The index of the first character to copy from __t. * @param __n The number of characters to copy from __t. * @param __a Allocator to use. @@ -601,16 +618,27 @@ template<typename _Tp, typename = _If_sv<_Tp, void>> basic_string(const _Tp& __t, size_type __pos, size_type __n, const _Alloc& __a = _Alloc()) - : basic_string(__sv_type(__t).substr(__pos, __n), __a) { } - + : basic_string(_S_to_string_view(__t).substr(__pos, __n), __a) { } + /** * @brief Construct string from a string_view. - * @param __sv Source string view. + * @param __t Source object convertible to string view. * @param __a Allocator to use (default is default allocator). */ + template<typename _Tp, typename = _If_sv<_Tp, void>> explicit - basic_string(__sv_type __sv, const _Alloc& __a = _Alloc()) - : basic_string(__sv.data(), __sv.size(), __a) { } + basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) + : basic_string(__sv_wrapper(_S_to_string_view(__t)), __a) { } + + /** + * @brief Only internally used: Construct string from a string view + * wrapper. + * @param __svw string view wrapper. + * @param __a Allocator to use. + */ + explicit + basic_string(__sv_wrapper __svw, const _Alloc& __a) + : basic_string(__svw._M_sv.data(), __svw._M_sv.size(), __a) { } #endif // C++17 /** @@ -756,12 +784,12 @@ #if __cplusplus > 201402L /** * @brief Set value to string constructed from a string_view. - * @param __sv A string_view. + * @param __svt An object convertible to string_view. */ - template<typename _Tp> - _If_sv<_Tp, basic_string&> - operator=(_Tp __sv) - { return this->assign(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator=(const _Tp& __svt) + { return this->assign(__svt); } /** * @brief Convert to a string_view. @@ -1157,12 +1185,13 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt An object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - operator+=(__sv_type __sv) - { return this->append(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator+=(const _Tp& __svt) + { return this->append(__svt); } #endif // C++17 /** @@ -1265,29 +1294,33 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt An object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - append(__sv_type __sv) - { return this->append(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->append(__sv.data(), __sv.size()); + } /** * @brief Append a range of characters from a string_view. - * @param __sv The string_view to be appended from. + * @param __svt An object convertible to string_view to be appended from. * @param __pos The position in the string_view to append from. * @param __n The number of characters to append from the string_view. * @return Reference to this string. */ template <typename _Tp> - _If_sv<_Tp, basic_string&> - append(const _Tp& __svt, size_type __pos, size_type __n = npos) - { - __sv_type __sv = __svt; - return _M_append(__sv.data() + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt, size_type __pos, size_type __n = npos) + { + __sv_type __sv = __svt; + return _M_append(__sv.data() + __sv._M_check(__pos, "basic_string::append"), __sv._M_limit(__pos, __n)); - } + } #endif // C++17 /** @@ -1433,29 +1466,33 @@ #if __cplusplus > 201402L /** * @brief Set value from a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @return Reference to this string. */ - basic_string& - assign(__sv_type __sv) - { return this->assign(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->assign(__sv.data(), __sv.size()); + } /** * @brief Set value from a range of characters in a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @param __pos The position in the string_view to assign from. * @param __n The number of characters to assign. * @return Reference to this string. */ - template <typename _Tp> - _If_sv<_Tp, basic_string&> - assign(const _Tp& __svt, size_type __pos, size_type __n = npos) - { - __sv_type __sv = __svt; - return _M_replace(size_type(0), this->size(), __sv.data() + template <typename _Tp> + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt, size_type __pos, size_type __n = npos) + { + __sv_type __sv = __svt; + return _M_replace(size_type(0), this->size(), __sv.data() + __sv._M_check(__pos, "basic_string::assign"), __sv._M_limit(__pos, __n)); - } + } #endif // C++17 #if __cplusplus >= 201103L @@ -1692,32 +1729,36 @@ /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - insert(size_type __pos, __sv_type __sv) - { return this->insert(__pos, __sv.data(), __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, basic_string&> + insert(size_type __pos, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->insert(__pos, __sv.data(), __sv.size()); + } /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos Iterator referencing position in string_view to insert * from. * @param __n The number of characters to insert. * @return Reference to this string. */ - template <typename _Tp> - _If_sv<_Tp, basic_string&> - insert(size_type __pos1, const _Tp& __svt, + template <typename _Tp> + _If_sv<_Tp, basic_string&> + insert(size_type __pos1, const _Tp& __svt, size_type __pos2, size_type __n = npos) - { - __sv_type __sv = __svt; - return this->replace(__pos1, size_type(0), __sv.data() + { + __sv_type __sv = __svt; + return this->replace(__pos1, size_type(0), __sv.data() + __sv._M_check(__pos2, "basic_string::insert"), __sv._M_limit(__pos2, __n)); - } + } #endif // C++17 /** @@ -2120,32 +2161,36 @@ * @brief Replace range of characters with string_view. * @param __pos The position to replace at. * @param __n The number of characters to replace. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - replace(size_type __pos, size_type __n, __sv_type __sv) - { return this->replace(__pos, __n, __sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + replace(size_type __pos, size_type __n, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__pos, __n, __sv.data(), __sv.size()); + } /** * @brief Replace range of characters with string_view. * @param __pos1 The position to replace at. * @param __n1 The number of characters to replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos2 The position in the string_view to insert from. * @param __n2 The number of characters to insert. * @return Reference to this string. */ - template <typename _Tp> - _If_sv<_Tp, basic_string&> - replace(size_type __pos1, size_type __n1, const _Tp& __svt, + template <typename _Tp> + _If_sv<_Tp, basic_string&> + replace(size_type __pos1, size_type __n1, const _Tp& __svt, size_type __pos2, size_type __n2 = npos) - { - __sv_type __sv = __svt; - return this->replace(__pos1, __n1, __sv.data() + { + __sv_type __sv = __svt; + return this->replace(__pos1, __n1, __sv.data() + __sv._M_check(__pos2, "basic_string::replace"), __sv._M_limit(__pos2, __n2)); - } + } /** * @brief Replace range of characters with string_view. @@ -2153,12 +2198,16 @@ to replace at. * @param __i2 An iterator referencing the end position for the replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @return Reference to this string. */ - basic_string& - replace(const_iterator __i1, const_iterator __i2, __sv_type __sv) - { return this->replace(__i1 - begin(), __i2 - __i1, __sv); } + template <typename _Tp> + _If_sv<_Tp, basic_string&> + replace(const_iterator __i1, const_iterator __i2, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__i1 - begin(), __i2 - __i1, __sv); + } #endif // C++17 private: @@ -2288,13 +2337,18 @@ #if __cplusplus > 201402L /** * @brief Find position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search from (default 0). * @return Index of start of first occurrence. */ - size_type - find(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2345,13 +2399,18 @@ #if __cplusplus > 201402L /** * @brief Find last position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search back from (default end). * @return Index of start of last occurrence. */ - size_type - rfind(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->rfind(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + rfind(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->rfind(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2419,13 +2478,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character of a string_view. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_first_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2497,13 +2562,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character of string. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_last_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2574,13 +2645,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt A object convertible to string_view containing characters + * to avoid. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_not_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_not_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_first_not_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2650,13 +2727,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt An object convertible to string_view containing + * characters to avoid. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_not_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_not_of(__sv.data(), __pos, __sv.size()); } + template <typename _Tp> + _If_sv<_Tp, size_type> + find_last_not_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -2754,12 +2837,14 @@ #if __cplusplus > 201402L /** * @brief Compare to a string_view. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare against. * @return Integer < 0, 0, or > 0. */ - int - compare(__sv_type __sv) const + template <typename _Tp> + _If_sv<_Tp, int> + compare(const _Tp& __svt) const noexcept(is_same<_Tp, __sv_type>::value) { + __sv_type __sv = __svt; const size_type __size = this->size(); const size_type __osize = __sv.size(); const size_type __len = std::min(__size, __osize); @@ -2774,18 +2859,24 @@ * @brief Compare to a string_view. * @param __pos A position in the string to start comparing from. * @param __n The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @return Integer < 0, 0, or > 0. */ - int - compare(size_type __pos, size_type __n, __sv_type __sv) const - { return __sv_type(*this).substr(__pos, __n).compare(__sv); } + template <typename _Tp> + _If_sv<_Tp, int> + compare(size_type __pos, size_type __n, const _Tp& __svt) const + { + __sv_type __sv = __svt; + return __sv_type(*this).substr(__pos, __n).compare(__sv); + } /** * @brief Compare to a string_view. * @param __pos1 A position in the string to start comparing from. * @param __n1 The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @param __pos2 A position in the string_view to start comparing from. * @param __n2 The number of characters to compare. * @return Integer < 0, 0, or > 0. @@ -3348,6 +3439,23 @@ __and_<is_convertible<const _Tp&, __sv_type>, __not_<is_convertible<const _Tp&, const _CharT*>>>::value, _Res>; + + // Performs an implicit conversion from _Tp to __sv_type. + template<typename _Tp> + static __sv_type _S_to_string_view(const _Tp& __svt) + { + return __svt; + } + + // Wraps a string_view by explicit conversion and thus + // allows to add an internal constructor that does not + // participate in overload resolution when a string_view + // is provided. + struct __sv_wrapper + { + explicit __sv_wrapper(__sv_type __sv) noexcept : _M_sv(__sv) {} + __sv_type _M_sv; + }; #endif public: @@ -3474,24 +3582,35 @@ #if __cplusplus > 201402L /** * @brief Construct string from a substring of a string_view. - * @param __t Source string view. + * @param __t Source object convertible to string view. * @param __pos The index of the first character to copy from __t. * @param __n The number of characters to copy from __t. * @param __a Allocator to use. */ - template<typename _Tp, typename = _If_sv<_Tp, void>> + template<typename _Tp, typename = _If_sv<_Tp, void>> basic_string(const _Tp& __t, size_type __pos, size_type __n, const _Alloc& __a = _Alloc()) - : basic_string(__sv_type(__t).substr(__pos, __n), __a) { } - + : basic_string(_S_to_string_view(__t).substr(__pos, __n), __a) { } + /** * @brief Construct string from a string_view. - * @param __sv Source string view. + * @param __t Source object convertible to string view. * @param __a Allocator to use (default is default allocator). */ + template<typename _Tp, typename = _If_sv<_Tp, void>> explicit - basic_string(__sv_type __sv, const _Alloc& __a = _Alloc()) - : basic_string(__sv.data(), __sv.size(), __a) { } + basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) + : basic_string(__sv_wrapper(_S_to_string_view(__t)), __a) { } + + /** + * @brief Only internally used: Construct string from a string view + * wrapper. + * @param __svw string view wrapper. + * @param __a Allocator to use. + */ + explicit + basic_string(__sv_wrapper __svw, const _Alloc& __a) + : basic_string(__svw._M_sv.data(), __svw._M_sv.size(), __a) { } #endif // C++17 /** @@ -3562,12 +3681,12 @@ #if __cplusplus > 201402L /** * @brief Set value to string constructed from a string_view. - * @param __sv A string_view. + * @param __svt An object convertible to string_view. */ - template<typename _Tp> - _If_sv<_Tp, basic_string&> - operator=(_Tp __sv) - { return this->assign(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator=(const _Tp& __svt) + { return this->assign(__svt); } /** * @brief Convert to a string_view. @@ -3984,12 +4103,13 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt The object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - operator+=(__sv_type __sv) - { return this->append(__sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + operator+=(const _Tp& __svt) + { return this->append(__svt); } #endif // C++17 /** @@ -4075,16 +4195,21 @@ #if __cplusplus > 201402L /** * @brief Append a string_view. - * @param __sv The string_view to be appended. + * @param __svt The object convertible to string_view to be appended. * @return Reference to this string. */ - basic_string& - append(__sv_type __sv) - { return this->append(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + append(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->append(__sv.data(), __sv.size()); + } /** * @brief Append a range of characters from a string_view. - * @param __sv The string_view to be appended from. + * @param __svt The object convertible to string_view to be appended + * from. * @param __pos The position in the string_view to append from. * @param __n The number of characters to append from the string_view. * @return Reference to this string. @@ -4228,16 +4353,20 @@ #if __cplusplus > 201402L /** * @brief Set value from a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @return Reference to this string. */ - basic_string& - assign(__sv_type __sv) - { return this->assign(__sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + assign(const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->assign(__sv.data(), __sv.size()); + } /** * @brief Set value from a range of characters in a string_view. - * @param __sv The source string_view. + * @param __svt The source object convertible to string_view. * @param __pos The position in the string_view to assign from. * @param __n The number of characters to assign. * @return Reference to this string. @@ -4432,17 +4561,21 @@ /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - insert(size_type __pos, __sv_type __sv) - { return this->insert(__pos, __sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + insert(size_type __pos, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->insert(__pos, __sv.data(), __sv.size()); + } /** * @brief Insert a string_view. * @param __pos Iterator referencing position in string to insert at. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos Iterator referencing position in string_view to insert * from. * @param __n The number of characters to insert. @@ -4819,18 +4952,22 @@ * @brief Replace range of characters with string_view. * @param __pos The position to replace at. * @param __n The number of characters to replace. - * @param __sv The string_view to insert. + * @param __svt The object convertible to string_view to insert. * @return Reference to this string. */ - basic_string& - replace(size_type __pos, size_type __n, __sv_type __sv) - { return this->replace(__pos, __n, __sv.data(), __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + replace(size_type __pos, size_type __n, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__pos, __n, __sv.data(), __sv.size()); + } /** * @brief Replace range of characters with string_view. * @param __pos1 The position to replace at. * @param __n1 The number of characters to replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @param __pos2 The position in the string_view to insert from. * @param __n2 The number of characters to insert. * @return Reference to this string. @@ -4852,12 +4989,16 @@ to replace at. * @param __i2 An iterator referencing the end position for the replace. - * @param __sv The string_view to insert from. + * @param __svt The object convertible to string_view to insert from. * @return Reference to this string. */ - basic_string& - replace(const_iterator __i1, const_iterator __i2, __sv_type __sv) - { return this->replace(__i1 - begin(), __i2 - __i1, __sv); } + template<typename _Tp> + _If_sv<_Tp, basic_string&> + replace(const_iterator __i1, const_iterator __i2, const _Tp& __svt) + { + __sv_type __sv = __svt; + return this->replace(__i1 - begin(), __i2 - __i1, __sv); + } #endif // C++17 private: @@ -5062,13 +5203,18 @@ #if __cplusplus > 201402L /** * @brief Find position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search from (default 0). * @return Index of start of first occurrence. */ - size_type - find(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5135,13 +5281,18 @@ #if __cplusplus > 201402L /** * @brief Find last position of a string_view. - * @param __sv The string_view to locate. + * @param __svt The object convertible to string_view to locate. * @param __pos Index of character to search back from (default end). * @return Index of start of last occurrence. */ - size_type - rfind(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->rfind(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + rfind(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->rfind(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5213,13 +5364,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character of a string_view. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_first_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5291,13 +5448,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character of string. - * @param __sv A string_view containing characters to locate. + * @param __svt An object convertible to string_view containing + * characters to locate. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_last_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5366,13 +5529,19 @@ #if __cplusplus > 201402L /** * @brief Find position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt An object convertible to string_view containing + * characters to avoid. * @param __pos Index of character to search from (default 0). * @return Index of first occurrence. */ - size_type - find_first_not_of(__sv_type __sv, size_type __pos = 0) const noexcept - { return this->find_first_not_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_first_not_of(const _Tp& __svt, size_type __pos = 0) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_first_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5442,13 +5611,19 @@ #if __cplusplus > 201402L /** * @brief Find last position of a character not in a string_view. - * @param __sv A string_view containing characters to avoid. + * @param __svt An object convertible to string_view containing + * characters to avoid. * @param __pos Index of character to search back from (default end). * @return Index of last occurrence. */ - size_type - find_last_not_of(__sv_type __sv, size_type __pos = npos) const noexcept - { return this->find_last_not_of(__sv.data(), __pos, __sv.size()); } + template<typename _Tp> + _If_sv<_Tp, size_type> + find_last_not_of(const _Tp& __svt, size_type __pos = npos) const + noexcept(is_same<_Tp, __sv_type>::value) + { + __sv_type __sv = __svt; + return this->find_last_not_of(__sv.data(), __pos, __sv.size()); + } #endif // C++17 /** @@ -5498,12 +5673,14 @@ #if __cplusplus > 201402L /** * @brief Compare to a string_view. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare against. * @return Integer < 0, 0, or > 0. */ - int - compare(__sv_type __sv) const + template<typename _Tp> + _If_sv<_Tp, int> + compare(const _Tp& __svt) const noexcept(is_same<_Tp, __sv_type>::value) { + __sv_type __sv = __svt; const size_type __size = this->size(); const size_type __osize = __sv.size(); const size_type __len = std::min(__size, __osize); @@ -5518,18 +5695,24 @@ * @brief Compare to a string_view. * @param __pos A position in the string to start comparing from. * @param __n The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @return Integer < 0, 0, or > 0. */ - int - compare(size_type __pos, size_type __n, __sv_type __sv) const - { return __sv_type(*this).substr(__pos, __n).compare(__sv); } + template<typename _Tp> + _If_sv<_Tp, int> + compare(size_type __pos, size_type __n, const _Tp& __svt) const + { + __sv_type __sv = __svt; + return __sv_type(*this).substr(__pos, __n).compare(__sv); + } /** * @brief Compare to a string_view. * @param __pos1 A position in the string to start comparing from. * @param __n1 The number of characters to compare. - * @param __sv A string_view to compare against. + * @param __svt An object convertible to string_view to compare + * against. * @param __pos2 A position in the string_view to start comparing from. * @param __n2 The number of characters to compare. * @return Integer < 0, 0, or > 0. Index: testsuite/21_strings/basic_string/79162.cc =================================================================== --- testsuite/21_strings/basic_string/79162.cc (nonexistent) +++ testsuite/21_strings/basic_string/79162.cc (working copy) @@ -0,0 +1,37 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <string> + +template <class DataType> +class opt : public DataType +{ + opt(const opt &) = delete; + opt &operator=(const opt &) = delete; +public: + opt() {} +}; + +int main() +{ + opt<std::string> PGOTestProfileFile; + std::string ProfileFileName; + ProfileFileName = PGOTestProfileFile; +} Index: testsuite/21_strings/basic_string/lwg2946.cc =================================================================== --- testsuite/21_strings/basic_string/lwg2946.cc (nonexistent) +++ testsuite/21_strings/basic_string/lwg2946.cc (working copy) @@ -0,0 +1,41 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <string> + +int main() +{ + std::string s({"abc", 1}); + s = {"abc", 1}; + s += {"abc", 1}; + s.append({"abc", 1}); + s.assign({"abc", 1}); + s.insert(0, {"abc", 1}); + s.replace(0, 1, {"abc", 1}); + s.replace(s.cbegin(), s.cbegin(), {"abc", 1}); + s.find({"abc", 1}); + s.rfind({"abc", 1}); + s.find_first_of({"abc", 1}); + s.find_last_of({"abc", 1}); + s.find_first_not_of({"abc", 1}); + s.find_last_not_of({"abc", 1}); + s.compare({"abc", 1}); + s.compare(0, 1, {"abc", 1}); +} ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2017-09-20 22:03 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <CAGNvRgCv1Y8a6DGO=p9g8FAve1-UKf53vshqFYtdmWkDUzn8+Q@mail.gmail.com> 2017-07-28 20:26 ` [PATCH] PR libstdc++/79162 ambiguity in string assignment due to string_view overload (LWG 2946) Tim Song 2017-07-28 20:29 ` Daniel Krügler 2017-07-28 20:40 ` Daniel Krügler 2017-07-30 13:01 ` Daniel Krügler 2017-08-18 18:27 ` Daniel Krügler 2017-09-04 15:48 ` Jonathan Wakely 2017-09-11 16:55 ` Jonathan Wakely 2017-09-20 15:36 ` Jonathan Wakely 2017-09-20 16:52 ` Jonathan Wakely 2017-09-20 18:00 ` Jonathan Wakely 2017-09-20 22:03 ` Jonathan Wakely 2017-07-28 20:07 Daniel Krügler
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).