`<format>`: Is `c` really a cromulent integer presentation type?
Open
Nobody has claimed this yet.
format
LWG issue needed
- Dominant language
- C++
- Stars
- 11.1k
- Forks
- 1.7k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 22
Description
https://godbolt.org/z/vac7s4rKn
#include <cassert>
#include <format>
#include <string>
using namespace std;
int main() {
// Everyone accepts:
assert(format("{0:#}", 77) == "77");
assert(format("{0:#d}", 77) == "77");
assert(format("{0:#b}", 77) == "0b1001101");
assert(format("{0:#B}", 77) == "0B1001101");
assert(format("{0:#o}", 77) == "0115");
assert(format("{0:#x}", 77) == "0x4d");
assert(format("{0:#X}", 77) == "0X4D");
assert(format("{0:c}", 77) == "M");
// libstdc++ 14.2 accepts, libc++ 18.1 and microsoft/STL 17.10 reject:
assert(format("{0:#c}", 77) == "M");
// 77 is an int, which is an arithmetic type other than charT and bool.
// 'c' is an integer presentation type.
// Therefore, I conclude that formatting 77 with "{0:#c}" is doubly valid.
// Here's the Standardese:
// N4988 [format.string.std]/7:
// "The # option causes the alternate form to be used for the conversion.
// This option is valid for arithmetic types other than charT and bool
// or when an integer presentation type is specified, and not otherwise."
// N4988 [format.string.std]/21:
// "The available integer presentation types for integral types other than bool and charT
// are specified in Table 72."
// Table 72 - Meaning of type options for integer types [tab:format.type.int]
// Type | Meaning
// -----|--------
// b | to_chars(first, last, value, 2); the base prefix is 0b.
// B | The same as b, except that the base prefix is 0B.
// c | Copies the character static_cast<charT>(value) to the output.
// | Throws format_error if value is not in the range of representable values for charT.
// [...]
}
With VS 2022 17.12 Preview 1:
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od /diagnostics:caret meow.cpp
meow.cpp
meow.cpp(18,5): error C7595: 'std::basic_format_string<char,int>::basic_format_string': call to immediate function is not a constant expression
assert(format("{0:#c}", 77) == "M");
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(1977,32): note: failure was caused by call of undefined function or one not declared 'constexpr'
_Throw_format_error("Hash/sign modifier requires an arithmetic presentation type");
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(1977,32): note: see usage of 'std::_Throw_format_error'
meow.cpp(18,5): note: the call stack of the evaluation (the oldest call first) is
assert(format("{0:#c}", 77) == "M");
^
meow.cpp(18,5): note: while evaluating function 'std::basic_format_string<char,int>::basic_format_string<char[7]>(const _Ty (&))'
with
[
_Ty=char [7]
]
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(3696,33): note: while evaluating function 'void std::_Parse_format_string<char,std::__p2286::_Format_checker<char,int>>(std::basic_string_view<char,std::char_traits<char>>,_HandlerT &&)'
with
[
_HandlerT=std::__p2286::_Format_checker<char,int>
]
_Parse_format_string(_Str, _Format_checker<_CharT, remove_cvref_t<_Args>...>{_Str, _Arg_types});
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(1551,42): note: while evaluating function 'const _CharT *std::_Parse_replacement_field<char,_HandlerT&>(const _CharT *,const _CharT *,std::__p2286::_Format_checker<_CharT,int>&)'
with
[
_CharT=char,
_HandlerT=std::__p2286::_Format_checker<char,int>
]
_First = _Parse_replacement_field(_OpeningCurl, _Last, _Handler);
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(1500,47): note: while evaluating function 'const _CharT *std::__p2286::_Format_checker<_CharT,int>::_On_format_specs(const size_t,const _CharT *,const _CharT *)'
with
[
_CharT=char
]
_First = _Handler._On_format_specs(_Adapter._Arg_id, _First + 1, _Last);
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(3592,42): note: while evaluating function 'std::_String_view_iterator<_Traits> std::__p2286::_Compile_time_parse_format_specs<int,std::basic_format_parse_context<char>>(_ParseContext &)'
with
[
_Traits=std::char_traits<char>,
_ParseContext=std::basic_format_parse_context<char>
]
auto _Iter = _Parse_funcs[_Id](_Parse_context); // TRANSITION, VSO-1451773 (workaround: named variable)
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(3568,23): note: while evaluating function 'std::_String_view_iterator<_Traits> std::__p2286::_Formatter_base<int,_CharT,std::_Basic_format_arg_type::_Int_type>::parse<std::basic_format_parse_context<_CharT>>(_Pc &)'
with
[
_Traits=std::char_traits<char>,
_CharT=std::__p2286::_Compile_time_parse_format_specs::_CharT,
_Pc=std::basic_format_parse_context<char>
]
return _Formatter.parse(_Pc);
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\__msvc_formatter.hpp(160,16): note: while evaluating function 'std::_String_view_iterator<_Traits> std::__p2286::_Formatter_base_parse<std::_Basic_format_arg_type::_Int_type,_CharT,_Pc>(std::_Dynamic_format_specs<_CharT> &,_Pc &)'
with
[
_Traits=std::char_traits<char>,
_CharT=std::__p2286::_Compile_time_parse_format_specs::_CharT,
_Pc=std::basic_format_parse_context<char>
]
return _Formatter_base_parse<_ArgType>(_Specs, _ParseCtx);
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(3656,41): note: while evaluating function 'const _CharT *std::_Parse_format_specs<_CharT,std::_Specs_checker<std::_Dynamic_specs_handler<_Pc>>&>(const _CharT *,const _CharT *,_Callbacks_type)'
with
[
_CharT=char,
_Pc=std::basic_format_parse_context<char>,
_Callbacks_type=std::_Specs_checker<std::_Dynamic_specs_handler<std::basic_format_parse_context<char>>> &
]
const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler);
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(1463,28): note: while evaluating function 'void std::_Specs_checker<std::_Dynamic_specs_handler<_Pc>>::_On_type<_CharT>(_CharT)'
with
[
_Pc=std::basic_format_parse_context<char>,
_CharT=char
]
_Callbacks._On_type(*_First);
^
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.42.34226\include\format(1977,32): note: while evaluating function 'void std::_Throw_format_error(const char *const )'
_Throw_format_error("Hash/sign modifier requires an arithmetic presentation type");
^
I believe that all of hash, sign, and zero are affected:
Someone should double-check my interpretation of the Standardese here, I'm not an expert.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproducer and the linked format implementation around stl/inc/format lines 1859-1861 and 1971-1985. Check the C++ standard wording quoted in the issue and compare handling of the #, sign, and zero options for the c presentation type. Done means the interpretation is confirmed and the affected behavior is covered consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100