PxxxxR0
Restrict what std::to_string may throw

New Proposal,

This version:
https://eisenwave.github.io/cpp-proposals/to-string-throws.html
Author:
Audience:
LWG
Project:
ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
Source:
eisenwave/cpp-proposals

Abstract

Add a Throws specification to std::to_string.

1. Introduction

After merging [P2587R3], [string.conversions] specifies std::to_string only through:

Returns: format("{}", val).

I believe this is needlessly under-specified because std::to_string can throw anything, given that it has no Throws specification. It would be better to reword it as an equivalence instead of merely specifying the result.

It is not unclear what this implementation freedom can be used for, and [P2587R3] doesn’t justify this design choice. A Throws specification would make it obvious that:

Note: The wording for std::to_string prior to [P2587R3] did not include a Throws specification either.

2. Implementation experience

libstdc++ is the only implementation which is reported to implement [P2587R3] at the time of writing; see basic_string.h The implementation is based on resize_and_overwrite and to_chars. It can only throw std::bad_alloc and would not benefit from the freedom to throw anything else.

3. Design considerations

A Throws specification is the most simple and direct way of conveying what can be thrown here, which is only std::bad_alloc.

Another wording strategy would be to add "Effects: Equivalent to: format("{}", val)", which inherits the Throws specification of [format.functions] vformat, which is specified through [format.err.report] paragraph 1. This strategy is worse because std::format_error is a red herring (cannot be thrown here) and because it takes too many indirections to get to std::bad_alloc.

4. Proposed wording

The proposed wording is relative to [N4950] with the changes from [P2587R3] applied.

In subclause 23.4.5 [string.conversions], update to_string as follows:

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

Throws: bad_alloc upon allocation failure.

Returns: format("{}, val).

In subclause 23.4.5 [string.conversions], update to_wstring as follows:

wstring to_wstring(int val);
wstring to_wstring(unsigned val);
wstring to_wstring(long val);
wstring to_wstring(unsigned long val);
wstring to_wstring(long long val);
wstring to_wstring(unsigned long long val);
wstring to_wstring(float val);
wstring to_wstring(double val);
wstring to_wstring(long double val);

Throws: bad_alloc upon allocation failure.

Returns: format(L"{}, val).

5. Acknowledgements

The current wording strategy of this proposal has been suggested by Jonathan Wakely.

References

Normative References

[N4950]
Thomas Köppe. Working Draft, Standard for Programming Language C++. 10 May 2023. URL: https://wg21.link/n4950

Informative References

[P2587R3]
Victor Zverovich. to_string or not to_string. 28 August 2022. URL: https://wg21.link/p2587r3