diff --git a/FWCore/Utilities/interface/Exception.h b/FWCore/Utilities/interface/Exception.h index 4a3d0b68aee90..e9e9ca502c614 100644 --- a/FWCore/Utilities/interface/Exception.h +++ b/FWCore/Utilities/interface/Exception.h @@ -38,6 +38,10 @@ #include #include #include +#include +#include + +#include "fmt/format.h" #include "FWCore/Utilities/interface/thread_safety_macros.h" #include "FWCore/Utilities/interface/Likely.h" @@ -45,17 +49,6 @@ namespace cms { - class Exception; - namespace detail { - // Used for SFINAE to control the instantiation of the stream insertion - // member template needed to support streaming output to an object - // of type cms::Exception, or a subclass of cms::Exception. - template - using exception_type = - std::enable_if_t>, std::remove_reference_t>; - - } // namespace detail - class dso_export Exception : public std::exception { public: explicit Exception(std::string const& aCategory); @@ -118,13 +111,20 @@ namespace cms { // template - friend typename detail::exception_type& operator<<(E&& e, T const& stuff); + requires std::derived_from, Exception> + friend E& operator<<(E&& e, T const& stuff); template - friend typename detail::exception_type& operator<<(E&& e, std::ostream& (*f)(std::ostream&)); + requires std::derived_from, Exception> + friend E& operator<<(E&& e, std::ostream& (*f)(std::ostream&)); template - friend typename detail::exception_type& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&)); + requires std::derived_from, Exception> + friend E& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&)); + + template + inline void format(fmt::format_string format, Args&&... args); + inline void vformat(std::string_view fmt, fmt::format_args args); // This function is deprecated and we are in the process of removing // all code that uses it from CMSSW. It will then be deleted. @@ -152,20 +152,30 @@ namespace cms { // -------- implementation --------- + template + inline void Exception::format(fmt::format_string format, Args&&... args) { + ost_ << fmt::format(std::move(format), std::forward(args)...); + } + + inline void Exception::vformat(std::string_view format, fmt::format_args args) { ost_ << fmt::vformat(format, args); } + template - inline typename detail::exception_type& operator<<(E&& e, T const& stuff) { + requires std::derived_from, Exception> + inline E& operator<<(E&& e, T const& stuff) { e.ost_ << stuff; return e; } template - inline typename detail::exception_type& operator<<(E&& e, std::ostream& (*f)(std::ostream&)) { + requires std::derived_from, Exception> + inline E& operator<<(E&& e, std::ostream& (*f)(std::ostream&)) { f(e.ost_); return e; } template - inline typename detail::exception_type& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&)) { + requires std::derived_from, Exception> + inline E& operator<<(E&& e, std::ios_base& (*f)(std::ios_base&)) { f(e.ost_); return e; } diff --git a/FWCore/Utilities/test/test_catch2_Exception.cc b/FWCore/Utilities/test/test_catch2_Exception.cc index 38133b5c2b7d8..479f59ab84edc 100644 --- a/FWCore/Utilities/test/test_catch2_Exception.cc +++ b/FWCore/Utilities/test/test_catch2_Exception.cc @@ -37,6 +37,17 @@ namespace { "\n" "Gave up\n"; + constexpr char expected_func4[] = + "An exception of category 'DataCorrupt' occurred.\n" + "Exception Message:\n" + "This is just a test: \n" + "double: 1.11111\n" + "float: 2.22222\n" + "uint: 75\n" + "string: a string\n" + "char*: a nonconst pointer\n" + "char[]: a c-style array\n"; + void func3() { double d = 1.11111; float f = 2.22222; @@ -77,10 +88,40 @@ namespace { } } + void func4() { + double d = 1.11111; + float f = 2.22222; + unsigned int i = 75U; + std::string s("a string"); + char* c1 = const_cast("a nonconst pointer"); + char c2[] = "a c-style array"; + Thing thing(4); + + // throw cms::Exception("DataCorrupt") + cms::Exception e("DataCorrupt"); + e.format( + "This is just a test: \n" + "double: {}\n" + "float: {}\n" + "uint: {}\n" + "string: {}\n" + "char*: {}\n" + "char[]: {}\n", + d, + f, + i, + s, + c1, + c2); + + throw e; + } + } // namespace TEST_CASE("Test cms::Exception", "[cms::Exception]") { SECTION("throw") { REQUIRE_THROWS_WITH(func1(), expected); } + SECTION("throw with format") { REQUIRE_THROWS_WITH(func4(), expected_func4); } SECTION("returnCode") { cms::Exception e1("ABC"); REQUIRE(e1.returnCode() == 8001);