T* val_;
};
+template <class T, class = void>
+class TryFormatValue {
+ public:
+ template <class FormatCallback>
+ static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
+ arg.error("No formatter available for this type");
+ }
+};
+
+template <class T>
+class TryFormatValue<
+ T,
+ typename std::enable_if<
+ 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
+ {
+ public:
+ template <class FormatCallback>
+ static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
+ FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
+ }
+};
+
// Partial specialization of FormatValue for other pointers
template <class T>
class FormatValue<
if (arg.keyEmpty()) {
FormatValue<void*>((void*)val_).format(arg, cb);
} else {
- FormatValue<typename std::decay<T>::type>(
- val_[arg.splitIntKey()]).format(arg, cb);
+ TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
}
}
private:
EXPECT_EQ("0020", vstr("{1:04}", p));
EXPECT_EQ("0020", fstr("{0[1]:04}", q));
EXPECT_EQ("0020", vstr("{1:04}", q));
+ EXPECT_NE("", fstr("{}", q));
EXPECT_EQ("0x", fstr("{}", p).substr(0, 2));
EXPECT_EQ("10", vstr("{}", p));
EXPECT_EQ("<key=hello", fstr("{:.10}", kv));
EXPECT_EQ("<key=hello, value=42>XX", fstr("{:X<23}", kv));
EXPECT_EQ("XX<key=hello, value=42>", fstr("{:X>23}", kv));
+ EXPECT_EQ("<key=hello, value=42>", fstr("{0[0]}", &kv));
+ EXPECT_NE("", fstr("{}", &kv));
+}
+
+namespace {
+
+struct Opaque {
+ int k;
+};
+
+} // namespace
+
+TEST(Format, Unformatted) {
+ Opaque o;
+ EXPECT_NE("", fstr("{}", &o));
+ EXPECT_THROW(fstr("{0[0]}", &o), std::invalid_argument);
}
TEST(Format, Nested) {