C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Should std::to_string be deprecated?

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Mon, 9 Oct 2023 10:08:56 +0100
On Mon, 9 Oct 2023, 09:04 Jonathan Sweemer, <sweemer_at_[hidden]> wrote:

> You're right, there's no advantage in constraining std::format, and now
> that I think about it, there's probably no advantage in constraining a
> generic version of std::to_string either, because I think it's more helpful
> for users to see a compilation failure related to a missing formatter (from
> the constructor of std::format_string) rather than a missing overload of
> std::to_string (from the failed constraint).
>

Yeah. If we wanted to make to_string an ADL customisation point that users
can overload in their own namespaces, the constant would be needed. But
std::formatter would be the customisation point, not the to_string function.





> So something like the following might be all that is needed to make
> std::to_string a generic shorthand for single-arg std::format. Note that I
> used a universal reference instead of the lvalue reference from your
> original reply so that the argument can be forwarded to std::format - does
> it make a difference?
>

Yes, generator-like types might only be non-const formattable, and passed
as an rvalue.



> template<typename T>
> auto to_string(T&& t) {
> return std::format("{}", std::forward<T>(t));
> }
>
> This is essentially the same thing that Grzegorz suggested as well, but
> personally I prefer putting it in std::to_string because if it's not going
> to be deprecated, then it should at least be made more generic.
>
>
> On Thu, Oct 5, 2023 at 11:22 PM Jonathan Wakely <cxx_at_[hidden]> wrote:
>
>>
>>
>> On Thu, 5 Oct 2023 at 14:14, Jonathan Sweemer <sweemer_at_[hidden]> wrote:
>>
>>> That would result in char being printed out as an int value, e.g. 65
>>> instead of 'A', which is inconsistent with std::format("{}", 'A'). If there
>>> is a generic version of std::to_string then it should produce the same
>>> result as std::format, no?
>>>
>>> By the way, in your earlier email you mentioned the formatable<char>
>>> concept
>>>
>>
>> That was a typo for formattable, but yes it's exists since C++23.
>>
>>
>>> to constrain a hypothetical generic version of std::to_string. Does this
>>> concept exist already, and if so, why isn't it used on std::format
>>> itself, which as far as I can tell, is currently unconstrained?
>>>
>>
>> What would be the advantage of constraining it? There's only one
>> std::format function, so either it compiles or it doesn't. You don't need
>> to select between different overloads based on constraints. Checking a
>> constraint would just make compilation slower.
>>
>> Constraining it would allow you to test whether std::format can be called
>> for a given argument type, but you can already use std::formattable to do
>> that (which would be faster to compile than testing whether a function
>> constrained with std::formattable can be called).
>>
>> But the real answer is probably just that the concept was added in C++23
>> and std::format was added in C++20, so it couldn't have been constrained
>> with a concept that didn't exist yet. I don't see a compelling reason to
>> add the constraint now.
>>
>>
>>>
>>> On Thu, Oct 5, 2023 at 9:52 PM Jonathan Wakely <cxx_at_[hidden]> wrote:
>>>
>>>>
>>>>
>>>> On Thu, 5 Oct 2023, 12:53 Jonathan Sweemer via Std-Proposals, <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>> I would say yes, if the general consensus is that std::to_string is
>>>>> useful and should not be deprecated, then at least it should be made more
>>>>> generic.
>>>>>
>>>>> The current list of overloads for std::to_string seems a bit arbitrary
>>>>> and incomplete to me, with char being the most error-prone example, as it
>>>>> happily binds to the overload taking int.
>>>>>
>>>>> If you know you're dealing with ints, then I agree that std::to_string
>>>>> provides a more simple syntax for converting to a string, but in any
>>>>> generic code you either have to use std::format (i.e. forget about
>>>>> std::to_string), or do something like the following to delegate between the
>>>>> two:
>>>>>
>>>>> template<typename T>
>>>>> concept to_stringable =
>>>>>
>>>>
>>>> requires(const T& t) {
>>>> { std::to_string(t) } -> std::same_as<std::string>;
>>>> };
>>>>
>>>> std::is_same_v<T, int> ||
>>>>> std::is_same_v<T, long> ||
>>>>> std::is_same_v<T, long long> ||
>>>>> std::is_same_v<T, unsigned> ||
>>>>> std::is_same_v<T, unsigned long> ||
>>>>> std::is_same_v<T, unsigned long long> ||
>>>>> std::is_same_v<T, float> ||
>>>>> std::is_same_v<T, double> ||
>>>>> std::is_same_v<T, long double>;
>>>>>
>>>>> template<typename T>
>>>>> auto generic_to_string(const T& t) {
>>>>> if constexpr (to_stringable<T>) {
>>>>> return std::to_string(t);
>>>>> } else {
>>>>> return std::format("{}", t);
>>>>> }
>>>>> }
>>>>>
>>>>> But the to_stringable concept is very brittle to maintain, because new
>>>>> overloads might be added in future versions of the standard, so a truly
>>>>> generic version of std::to_string would be more desirable in my view.
>>>>>
>>>>>
>>>>> On Thu, Oct 5, 2023 at 4:56 PM Giuseppe D'Angelo via Std-Proposals <
>>>>> std-proposals_at_[hidden]> wrote:
>>>>>
>>>>>> Il 04/10/23 22:38, Victor Zverovich via Std-Proposals ha scritto:
>>>>>> > At the very least std::to_string is a useful shorthand notation for
>>>>>> > std::format for numeric types.
>>>>>> >
>>>>>>
>>>>>> But this prompts the question: would it would make sense to have a
>>>>>> overload `to_string` taking just any formattable type?
>>>>>>
>>>>>> Thanks,
>>>>>> --
>>>>>> Giuseppe D'Angelo
>>>>>> --
>>>>>> Std-Proposals mailing list
>>>>>> Std-Proposals_at_[hidden]
>>>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>>>>
>>>>> --
>>>>> Std-Proposals mailing list
>>>>> Std-Proposals_at_[hidden]
>>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>>>
>>>>

Received on 2023-10-09 09:09:11