Skip to content

Commit 8c13810

Browse files
committed
Updated cms::Exception using modern C++
- Added format option - Use concepts to constrain operator<<
1 parent 1d7ff69 commit 8c13810

File tree

2 files changed

+68
-17
lines changed

2 files changed

+68
-17
lines changed

FWCore/Utilities/interface/Exception.h

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,17 @@
3838
#include <string>
3939
#include <exception>
4040
#include <type_traits>
41+
#include <string_view>
42+
#include <concepts>
43+
44+
#include "fmt/format.h"
4145

4246
#include "FWCore/Utilities/interface/thread_safety_macros.h"
4347
#include "FWCore/Utilities/interface/Likely.h"
4448
#include "FWCore/Utilities/interface/Visibility.h"
4549

4650
namespace cms {
4751

48-
class Exception;
49-
namespace detail {
50-
// Used for SFINAE to control the instantiation of the stream insertion
51-
// member template needed to support streaming output to an object
52-
// of type cms::Exception, or a subclass of cms::Exception.
53-
template <typename E>
54-
using exception_type =
55-
std::enable_if_t<std::is_base_of_v<Exception, std::remove_reference_t<E>>, std::remove_reference_t<E>>;
56-
57-
} // namespace detail
58-
5952
class dso_export Exception : public std::exception {
6053
public:
6154
explicit Exception(std::string const& aCategory);
@@ -118,13 +111,20 @@ namespace cms {
118111
//
119112

120113
template <typename E, typename T>
121-
friend typename detail::exception_type<E>& operator<<(E&& e, T const& stuff);
114+
requires std::derived_from<std::remove_reference_t<E>, Exception>
115+
friend E& operator<<(E&& e, T const& stuff);
122116

123117
template <typename E>
124-
friend typename detail::exception_type<E>& operator<<(E&& e, std::ostream& (*f)(std::ostream&));
118+
requires std::derived_from<std::remove_reference_t<E>, Exception>
119+
friend E& operator<<(E&& e, std::ostream& (*f)(std::ostream&));
125120

126121
template <typename E>
127-
friend typename detail::exception_type<E>& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&));
122+
requires std::derived_from<std::remove_reference_t<E>, Exception>
123+
friend E& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&));
124+
125+
template <typename... Args>
126+
inline void format(fmt::format_string<Args...> format, Args&&... args);
127+
inline void vformat(std::string_view fmt, fmt::format_args args);
128128

129129
// This function is deprecated and we are in the process of removing
130130
// all code that uses it from CMSSW. It will then be deleted.
@@ -152,20 +152,30 @@ namespace cms {
152152

153153
// -------- implementation ---------
154154

155+
template <typename... Args>
156+
inline void Exception::format(fmt::format_string<Args...> format, Args&&... args) {
157+
ost_ << fmt::format(std::move(format), std::forward<Args>(args)...);
158+
}
159+
160+
inline void Exception::vformat(std::string_view format, fmt::format_args args) { ost_ << fmt::vformat(format, args); }
161+
155162
template <typename E, typename T>
156-
inline typename detail::exception_type<E>& operator<<(E&& e, T const& stuff) {
163+
requires std::derived_from<std::remove_reference_t<E>, Exception>
164+
inline E& operator<<(E&& e, T const& stuff) {
157165
e.ost_ << stuff;
158166
return e;
159167
}
160168

161169
template <typename E>
162-
inline typename detail::exception_type<E>& operator<<(E&& e, std::ostream& (*f)(std::ostream&)) {
170+
requires std::derived_from<std::remove_reference_t<E>, Exception>
171+
inline E& operator<<(E&& e, std::ostream& (*f)(std::ostream&)) {
163172
f(e.ost_);
164173
return e;
165174
}
166175

167176
template <typename E>
168-
inline typename detail::exception_type<E>& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&)) {
177+
requires std::derived_from<std::remove_reference_t<E>, Exception>
178+
inline E& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&)) {
169179
f(e.ost_);
170180
return e;
171181
}

FWCore/Utilities/test/test_catch2_Exception.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ namespace {
3737
"\n"
3838
"Gave up\n";
3939

40+
constexpr char expected_func4[] =
41+
"An exception of category 'DataCorrupt' occurred.\n"
42+
"Exception Message:\n"
43+
"This is just a test: \n"
44+
"double: 1.11111\n"
45+
"float: 2.22222\n"
46+
"uint: 75\n"
47+
"string: a string\n"
48+
"char*: a nonconst pointer\n"
49+
"char[]: a c-style array\n";
50+
4051
void func3() {
4152
double d = 1.11111;
4253
float f = 2.22222;
@@ -77,10 +88,40 @@ namespace {
7788
}
7889
}
7990

91+
void func4() {
92+
double d = 1.11111;
93+
float f = 2.22222;
94+
unsigned int i = 75U;
95+
std::string s("a string");
96+
char* c1 = const_cast<char*>("a nonconst pointer");
97+
char c2[] = "a c-style array";
98+
Thing thing(4);
99+
100+
// throw cms::Exception("DataCorrupt")
101+
cms::Exception e("DataCorrupt");
102+
e.format(
103+
"This is just a test: \n"
104+
"double: {}\n"
105+
"float: {}\n"
106+
"uint: {}\n"
107+
"string: {}\n"
108+
"char*: {}\n"
109+
"char[]: {}\n",
110+
d,
111+
f,
112+
i,
113+
s,
114+
c1,
115+
c2);
116+
117+
throw e;
118+
}
119+
80120
} // namespace
81121

82122
TEST_CASE("Test cms::Exception", "[cms::Exception]") {
83123
SECTION("throw") { REQUIRE_THROWS_WITH(func1(), expected); }
124+
SECTION("throw with format") { REQUIRE_THROWS_WITH(func4(), expected_func4); }
84125
SECTION("returnCode") {
85126
cms::Exception e1("ABC");
86127
REQUIRE(e1.returnCode() == 8001);

0 commit comments

Comments
 (0)