Skip to content

Commit e38838e

Browse files
committed
Add <format> format specifiers to string interpolation
Example: `(x.price(): <10.2f)$` is a space-padded left-aligned 10-width 2-precision value. When people complain about <iostream>, they're usually complaining about `<<` everywhere to concatenate elements, and the ugliness of the `<iomanip>` manipulators (and locales but that's another topic). Cpp2 loves streams, but I have to agree that this iomanip code today is pretty horrible: std::cout << std::left << std::setw(20) << x.name() << " color " << std::left << std::setw(10) << x.color() << " price " << std::setw(10) << std::setprecision(3) << x.price() << " in stock = " << std::boolalpha << (x.count() > 0) << "\n"; With this commit, you get the same formatted output with string interpolation and a single `<<`: std::cout << "(x.name():20)$ color (x.color():10)$ price (x.price(): <10.2f)$ in stock = (x.count() > 0)$\n"; Both versions print the same thing (see `pure2-interpolation.cpp2`): Dog kennel color mauve price 3.14 in stock = true
1 parent 874fa8d commit e38838e

12 files changed

+158
-40
lines changed

include/cpp2util.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
#endif
116116
#include <cwchar>
117117
#include <cwctype>
118-
#ifdef __cpp_lib_format
118+
#if defined(__cpp_lib_format) || (defined(_MSC_VER) && _MSC_VER >= 1929)
119119
#include <format>
120120
#endif
121121
#include <string>
@@ -221,6 +221,9 @@
221221
#include <concepts>
222222
#include <system_error>
223223
#include <limits>
224+
#if defined(__cpp_lib_format) || (defined(_MSC_VER) && _MSC_VER >= 1929)
225+
#include <format>
226+
#endif
224227

225228
#ifndef CPP2_NO_EXCEPTIONS
226229
#include <exception>
@@ -885,6 +888,23 @@ inline auto to_string(std::tuple<Ts...> const& t) -> std::string
885888
}
886889
}
887890

891+
// MSVC supports it but doesn't define __cpp_lib_format until the ABI stablizes, but here
892+
// don't care about that, so consider it as supported since VS 2019 16.10 (_MSC_VER 1929)
893+
#if defined(__cpp_lib_format) || (defined(_MSC_VER) && _MSC_VER >= 1929)
894+
inline auto to_string(auto&& value, std::string_view fmt) -> std::string
895+
{
896+
return std::vformat(fmt, std::make_format_args(CPP2_FORWARD(value)));
897+
}
898+
#else
899+
inline auto to_string(auto&& value, std::string_view) -> std::string
900+
{
901+
// This Cpp1 implementation does not support <format>-ted string interpolation
902+
// so the best we can do is ignore the formatting request (degraded operation
903+
// seems better than a dynamic error message string or a hard error)
904+
return to_string(CPP2_FORWARD(value));
905+
}
906+
#endif
907+
888908

889909
//-----------------------------------------------------------------------
890910
//
Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11

2+
item: @struct type = {
3+
name : (this) -> std::string = "Dog kennel";
4+
color: (this) -> std::string = "mauve";
5+
price: (this) -> double = 3.14;
6+
count: (this) -> int = 42;
7+
}
8+
29
main: ()->int = {
3-
x := 0;
4-
std::cout << "g(x)$g(x)$g" << "\n";
5-
std::cout << "(x)$g(x)$g" << "\n";
6-
std::cout << "(x)$g(x)$" << "\n";
7-
std::cout << "(x)$(x)$" << "\n";
8-
std::cout << "\"(x)$\"" << "\n";
9-
std::cout << "\"(x)$" << "\n";
10-
std::cout << "\"" << "\n";
11-
std::cout << "" << "\n";
12-
std::cout << "pl(ug$h" << "\n";
13-
std::cout << "(x)$pl(ug$h" << "\n";
10+
11+
(x := 0) {
12+
std::cout << "g(x)$g(x)$g" << "\n";
13+
std::cout << "(x)$g(x)$g" << "\n";
14+
std::cout << "(x)$g(x)$" << "\n";
15+
std::cout << "(x)$(x)$" << "\n";
16+
std::cout << "\"(x)$\"" << "\n";
17+
std::cout << "\"(x)$" << "\n";
18+
std::cout << "\"" << "\n";
19+
std::cout << "" << "\n";
20+
std::cout << "pl(ug$h" << "\n";
21+
std::cout << "(x)$pl(ug$h" << "\n";
22+
23+
}
24+
25+
(x := item()) {
26+
std::cout << std::left << std::setw(20) << x.name() << " color " << std::left << std::setw(10) << x.color() << " price " << std::setw(10) << std::setprecision(3) << x.price() << " in stock = " << std::boolalpha << (x.count() > 0) << "\n";
27+
28+
std::cout << "(x.name():20)$ color (x.color():10)$ price (x.price(): <10.2f)$ in stock = (x.count() > 0)$\n";
29+
}
30+
1431
}

regression-tests/test-results/clang-12/pure2-interpolation.cpp.execution

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ g0g0g
88

99
pl(ug$h
1010
0pl(ug$h
11+
Dog kennel color mauve price 3.14 in stock = true
12+
Dog kennel color mauve price 3.140000 in stock = true

regression-tests/test-results/gcc-10/pure2-bugfix-for-requires-clause-in-forward-declaration.cpp.output

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:46: error: expect
1111
In file included from pure2-bugfix-for-requires-clause-in-forward-declaration.cpp:7:
1212
../../../include/cpp2util.h:10005:47: error: static assertion failed: GCC 11 or higher is required to support variables and type-scope functions that have a 'requires' clause. This includes a type-scope 'forward' parameter of non-wildcard type, such as 'func: (this, forward s: std::string)', which relies on being able to add a 'requires' clause - in that case, use 'forward s: _' instead if you need the result to compile with GCC 10.
1313
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:4:1: note: in expansion of macro ‘CPP2_REQUIRES_’
14-
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:3: error: no declaration matches ‘element::element(auto:81&&) requires is_same_v<typename std::remove_cv<typename std::remove_reference<decltype(element::__ct ::n)>::type>::type, std::__cxx11::string>’
14+
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:3: error: no declaration matches ‘element::element(auto:82&&) requires is_same_v<typename std::remove_cv<typename std::remove_reference<decltype(element::__ct ::n)>::type>::type, std::__cxx11::string>’
1515
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:5:11: note: candidates are: ‘element::element(const element&)’
16-
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp:16:20: note: ‘template<class auto:79> element::element(auto:79&&)’
16+
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp:16:20: note: ‘template<class auto:80> element::element(auto:80&&)’
1717
16 | public: explicit element(auto&& n)
1818
| ^~~~~~~
1919
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp:14:7: note: ‘class element’ defined here
2020
14 | class element {
2121
| ^~~~~~~
2222
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:3: error: expected unqualified-id before ‘{’ token
23-
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:8: error: no declaration matches ‘element& element::operator=(auto:82&&) requires is_same_v<typename std::remove_cv<typename std::remove_reference<decltype(element::operator=::n)>::type>::type, std::__cxx11::string>’
23+
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:8: error: no declaration matches ‘element& element::operator=(auto:83&&) requires is_same_v<typename std::remove_cv<typename std::remove_reference<decltype(element::operator=::n)>::type>::type, std::__cxx11::string>’
2424
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:6:16: note: candidates are: ‘void element::operator=(const element&)’
25-
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:16: note: ‘template<class auto:80> element& element::operator=(auto:80&&)’
25+
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2:3:16: note: ‘template<class auto:81> element& element::operator=(auto:81&&)’
2626
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp:14:7: note: ‘class element’ defined here
2727
14 | class element {
2828
| ^~~~~~~

regression-tests/test-results/gcc-10/pure2-interpolation.cpp.execution

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ g0g0g
88

99
pl(ug$h
1010
0pl(ug$h
11+
Dog kennel color mauve price 3.14 in stock = true
12+
Dog kennel color mauve price 3.140000 in stock = true

regression-tests/test-results/gcc-13/pure2-interpolation.cpp.execution

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ g0g0g
88

99
pl(ug$h
1010
0pl(ug$h
11+
Dog kennel color mauve price 3.14 in stock = true
12+
Dog kennel color mauve price 3.14 in stock = true

regression-tests/test-results/msvc-2022/pure2-interpolation.cpp.execution

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ g0g0g
88

99
pl(ug$h
1010
0pl(ug$h
11+
Dog kennel color mauve price 3.14 in stock = true
12+
Dog kennel color mauve price 3.14 in stock = true

regression-tests/test-results/pure2-interpolation.cpp

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,64 @@
77
#include "cpp2util.h"
88

99

10+
#line 2 "pure2-interpolation.cpp2"
11+
class item;
12+
1013

1114
//=== Cpp2 type definitions and function declarations ===========================
1215

1316

1417
#line 2 "pure2-interpolation.cpp2"
18+
class item {
19+
public: [[nodiscard]] auto name() const& -> std::string;
20+
public: [[nodiscard]] auto color() const& -> std::string;
21+
public: [[nodiscard]] auto price() const& -> double;
22+
public: [[nodiscard]] auto count() const& -> int;
23+
};
24+
1525
[[nodiscard]] auto main() -> int;
16-
26+
1727

1828
//=== Cpp2 function definitions =================================================
1929

2030

21-
#line 2 "pure2-interpolation.cpp2"
31+
#line 3 "pure2-interpolation.cpp2"
32+
[[nodiscard]] auto item::name() const& -> std::string { return "Dog kennel"; }
33+
[[nodiscard]] auto item::color() const& -> std::string { return "mauve"; }
34+
[[nodiscard]] auto item::price() const& -> double { return 3.14; }
35+
[[nodiscard]] auto item::count() const& -> int { return 42; }
36+
37+
#line 9 "pure2-interpolation.cpp2"
2238
[[nodiscard]] auto main() -> int{
23-
auto x {0};
24-
std::cout << "g" + cpp2::to_string(x) + "g" + cpp2::to_string(x) + "g" << "\n";
25-
std::cout << cpp2::to_string(x) + "g" + cpp2::to_string(x) + "g" << "\n";
26-
std::cout << cpp2::to_string(x) + "g" + cpp2::to_string(x) << "\n";
27-
std::cout << cpp2::to_string(x) + cpp2::to_string(x) << "\n";
28-
std::cout << "\"" + cpp2::to_string(x) + "\"" << "\n";
29-
std::cout << "\"" + cpp2::to_string(x) << "\n";
30-
std::cout << "\"" << "\n";
31-
std::cout << "" << "\n";
32-
std::cout << "pl(ug$h" << "\n";
33-
std::cout << cpp2::to_string(std::move(x)) + "pl(ug$h" << "\n";
39+
{
40+
auto x = 0;
41+
42+
#line 11 "pure2-interpolation.cpp2"
43+
{
44+
std::cout << "g" + cpp2::to_string(x) + "g" + cpp2::to_string(x) + "g" << "\n";
45+
std::cout << cpp2::to_string(x) + "g" + cpp2::to_string(x) + "g" << "\n";
46+
std::cout << cpp2::to_string(x) + "g" + cpp2::to_string(x) << "\n";
47+
std::cout << cpp2::to_string(x) + cpp2::to_string(x) << "\n";
48+
std::cout << "\"" + cpp2::to_string(x) + "\"" << "\n";
49+
std::cout << "\"" + cpp2::to_string(x) << "\n";
50+
std::cout << "\"" << "\n";
51+
std::cout << "" << "\n";
52+
std::cout << "pl(ug$h" << "\n";
53+
std::cout << cpp2::to_string(x) + "pl(ug$h" << "\n";
54+
55+
}
56+
}
57+
{
58+
auto x = item();
59+
60+
#line 25 "pure2-interpolation.cpp2"
61+
{
62+
std::cout << std::left << std::setw(20) << CPP2_UFCS_0(name, x) << " color " << std::left << std::setw(10) << CPP2_UFCS_0(color, x) << " price " << std::setw(10) << std::setprecision(3) << CPP2_UFCS_0(price, x) << " in stock = " << std::boolalpha << (cpp2::cmp_greater(CPP2_UFCS_0(count, x),0)) << "\n";
63+
64+
std::cout << cpp2::to_string(CPP2_UFCS_0(name, x), "{:20}") + " color " + cpp2::to_string(CPP2_UFCS_0(color, x), "{:10}") + " price " + cpp2::to_string(CPP2_UFCS_0(price, x), "{: <10.2f}") + " in stock = " + cpp2::to_string(cpp2::cmp_greater(CPP2_UFCS_0(count, std::move(x)),0)) + "\n";
65+
}
66+
}
67+
68+
#line 31 "pure2-interpolation.cpp2"
3469
}
3570

regression-tests/test-results/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
cppfront compiler v0.2.1 Build 8922:0931
2+
cppfront compiler v0.2.1 Build 8923:1137
33
Copyright(c) Herb Sutter All rights reserved
44

55
SPDX-License-Identifier: CC-BY-NC-ND-4.0

source/build.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"8922:0931"
1+
"8923:1137"

0 commit comments

Comments
 (0)