toAppend<Tgt>(static_cast<Intermediate>(value), result);
}
+#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+// std::underlying_type became available by gcc 4.7.0
+
+/**
+ * Enumerated values get appended as integers.
+ */
+template <class Tgt, class Src>
+typename std::enable_if<
+ std::is_enum<Src>::value && detail::IsSomeString<Tgt>::value>::type
+toAppend(Src value, Tgt * result) {
+ toAppend(
+ static_cast<typename std::underlying_type<Src>::type>(value), result);
+}
+
+#else
+
/**
* Enumerated values get appended as integers.
*/
}
}
+#endif // gcc 4.7 onwards
+
/*******************************************************************************
* Conversions from floating-point types to string types.
******************************************************************************/
* Enum to anything and back
******************************************************************************/
+#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+// std::underlying_type became available by gcc 4.7.0
+
+template <class Tgt, class Src>
+typename std::enable_if<std::is_enum<Src>::value, Tgt>::type
+to(const Src & value) {
+ return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(value));
+}
+
+template <class Tgt, class Src>
+typename std::enable_if<std::is_enum<Tgt>::value, Tgt>::type
+to(const Src & value) {
+ return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
+}
+
+#else
+
template <class Tgt, class Src>
typename std::enable_if<std::is_enum<Src>::value, Tgt>::type
to(const Src & value) {
- // TODO: uncomment this when underlying_type is available
- // return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(
- // value));
/* static */ if (Src(-1) < 0) {
/* static */ if (sizeof(Src) <= sizeof(int)) {
return to<Tgt>(static_cast<int>(value));
template <class Tgt, class Src>
typename std::enable_if<std::is_enum<Tgt>::value, Tgt>::type
to(const Src & value) {
- // TODO: uncomment this when underlying_type is available
- // return static_cast<Tgt>(
- // to<typename std::underlying_type<Tgt>::type>(value));
/* static */ if (Tgt(-1) < 0) {
/* static */ if (sizeof(Tgt) <= sizeof(int)) {
return static_cast<Tgt>(to<int>(value));
}
}
+#endif // gcc 4.7 onwards
+
} // namespace folly
// FOLLY_CONV_INTERNAL is defined by Conv.cpp. Keep the FOLLY_RANGE_CHECK
TEST(Conv, IntToEnum) {
enum A { x = 42, y = 420 };
auto i = to<A>(42);
- EXPECT_EQ(i, A::x);
+ EXPECT_EQ(i, x);
auto j = to<A>(100);
EXPECT_EQ(j, 100);
try {
}
}
+TEST(Conv, UnsignedEnum) {
+ enum E : uint32_t { x = 3000000000U };
+ auto u = to<uint32_t>(x);
+ EXPECT_EQ(u, 3000000000U);
+ auto s = to<string>(x);
+ EXPECT_EQ("3000000000", s);
+ auto e = to<E>(3000000000U);
+ EXPECT_EQ(e, x);
+ try {
+ auto i = to<int32_t>(x);
+ LOG(ERROR) << to<uint32_t>(x);
+ EXPECT_TRUE(false);
+ } catch (std::range_error& e) {
+ }
+}
+
+#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+// to<enum class> and to(enum class) only supported in gcc 4.7 onwards
+
+TEST(Conv, UnsignedEnumClass) {
+ enum class E : uint32_t { x = 3000000000U };
+ auto u = to<uint32_t>(E::x);
+ EXPECT_GT(u, 0);
+ EXPECT_EQ(u, 3000000000U);
+ auto s = to<string>(E::x);
+ EXPECT_EQ("3000000000", s);
+ auto e = to<E>(3000000000U);
+ EXPECT_EQ(e, E::x);
+ try {
+ auto i = to<int32_t>(E::x);
+ LOG(ERROR) << to<uint32_t>(E::x);
+ EXPECT_TRUE(false);
+ } catch (std::range_error& e) {
+ }
+}
+
+// Multi-argument to<string> uses toAppend, a different code path than
+// to<string>(enum).
+TEST(Conv, EnumClassToString) {
+ enum class A { x = 4, y = 420, z = 65 };
+ EXPECT_EQ("foo.4", to<string>("foo.", A::x));
+ EXPECT_EQ("foo.420", to<string>("foo.", A::y));
+ EXPECT_EQ("foo.65", to<string>("foo.", A::z));
+}
+
+#endif // gcc 4.7 onwards
+
template<typename Src>
void testStr2Bool() {
EXPECT_FALSE(to<bool>(Src("0")));