[caffe2] Make c10::str works with scoped enum (#152705) (#152714)

Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/152705

Test Plan:
```
buck2 test fbcode//caffe2/c10/test:util_base_tests --fail-fast
```

Differential Revision: D74087796

Pull Request resolved: https://github.com/pytorch/pytorch/pull/152714
Approved by: https://github.com/Skylion007
This commit is contained in:
TJ Yin
2025-05-13 21:05:33 +00:00
committed by PyTorch MergeBot
parent e8596c291b
commit 81719ebde3
2 changed files with 31 additions and 3 deletions

View File

@ -163,4 +163,19 @@ TEST(SplitTest, ConsecutiveDelimiters) {
EXPECT_EQ("atom2", result[2]);
}
} // namespace test_split
namespace test_str_enum {
TEST(StringUtilTest, testStrEnum) {
enum class Foo { Bar = 1, Baz = 2 };
EXPECT_EQ(c10::str(Foo::Baz, Foo::Bar), "21");
enum UnscopedEnum { Bar2 = 1, Baz2 = 2 };
EXPECT_EQ(c10::str(Baz2, Bar2), "21");
static_assert(c10::detail::Streamable<int>::value);
static_assert(!c10::detail::Streamable<Foo>::value);
static_assert(c10::detail::Streamable<UnscopedEnum>::value);
}
} // namespace test_str_enum
} // namespace

View File

@ -10,6 +10,7 @@
#include <sstream>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
C10_CLANG_DIAGNOSTIC_PUSH()
@ -51,11 +52,23 @@ inline std::ostream& _str(std::ostream& ss) {
return ss;
}
template <class T, class = std::ostream&>
struct Streamable : std::false_type {};
template <class T>
struct Streamable<T, decltype(std::declval<std::ostream&>() << T{})>
: std::true_type {};
template <typename T>
inline std::ostream& _str(std::ostream& ss, const T& t) {
// NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
ss << t;
return ss;
if constexpr (std::is_enum_v<T> && !Streamable<T>::value) {
// NOLINTNEXTLINE(modernize-type-traits)
return _str(ss, static_cast<typename std::underlying_type<T>::type>(t));
} else {
// NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
ss << t;
return ss;
}
}
template <typename T>