diff --git a/format.cc b/format.cc index e413f13d..e1bf382e 100644 --- a/format.cc +++ b/format.cc @@ -579,38 +579,38 @@ void fmt::BasicWriter::write_str( } template -inline const Arg &fmt::BasicFormatter::parse_arg_index(const Char *&s) { +inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; - const Arg *arg = *s < '0' || *s > '9' ? + Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(parse_nonnegative_int(s), error); if (error) throw FormatError(*s != '}' && *s != ':' ? "invalid format string" : error); - return *arg; + return arg; } -const Arg *fmt::internal::FormatterBase::do_get_arg( +Arg fmt::internal::FormatterBase::do_get_arg( unsigned arg_index, const char *&error) { - if (arg_index < args_.size()) - return &args_[arg_index]; - error = "argument index out of range"; - return 0; + Arg arg = args_[arg_index]; + if (arg.type == Arg::NONE) + error = "argument index out of range"; + return arg; } -inline const Arg *fmt::internal::FormatterBase::next_arg(const char *&error) { +inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { if (next_arg_index_ >= 0) return do_get_arg(next_arg_index_++, error); error = "cannot switch from manual to automatic argument indexing"; - return 0; + return Arg(); } -inline const Arg *fmt::internal::FormatterBase::get_arg( +inline Arg fmt::internal::FormatterBase::get_arg( unsigned arg_index, const char *&error) { if (next_arg_index_ <= 0) { next_arg_index_ = -1; return do_get_arg(arg_index, error); } error = "cannot switch from automatic to manual argument indexing"; - return 0; + return Arg(); } template @@ -641,14 +641,14 @@ void fmt::internal::PrintfFormatter::parse_flags( } template -const Arg &fmt::internal::PrintfFormatter::get_arg( +Arg fmt::internal::PrintfFormatter::get_arg( const Char *s, unsigned arg_index) { const char *error = 0; - const Arg *arg = arg_index == UINT_MAX ? + Arg arg = arg_index == UINT_MAX ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); if (error) throw FormatError(!*s ? "invalid format string" : error); - return *arg; + return arg; } template diff --git a/format.h b/format.h index 617dd000..ab9dd497 100644 --- a/format.h +++ b/format.h @@ -608,16 +608,7 @@ struct NonZero<0> { }; // A formatting argument. It is a POD type to allow storage in internal::Array. -struct Arg { - enum Type { - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - STRING, WSTRING, POINTER, CUSTOM - }; - Type type; - +struct ArgBase { template struct StringValue { const Char *value; @@ -646,9 +637,98 @@ struct Arg { }; }; +struct Arg : public ArgBase { + enum Type { + NONE, + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + STRING, WSTRING, POINTER, CUSTOM + }; + Type type; +}; + +struct None {}; + +template +struct ArgType { + static const fmt::ULongLong TYPE = + ArgType<1, T0>::TYPE | (ArgType<1, T1>::TYPE << 4) | + (ArgType<1, T2>::TYPE << 8) | (ArgType<1, T3>::TYPE << 12) | + (ArgType<1, T4>::TYPE << 16) | (ArgType<1, T5>::TYPE << 20) | + (ArgType<1, T6>::TYPE << 24) | (ArgType<1, T7>::TYPE << 28) | + (ArgType<1, T8>::TYPE << 32) | (ArgType<1, T9>::TYPE << 36) | + (ArgType<1, T10>::TYPE << 40) | (ArgType<1, T11>::TYPE << 44) | + (ArgType<1, T12>::TYPE << 48) | (ArgType<1, T13>::TYPE << 52) | + (ArgType<1, T14>::TYPE << 56); +}; + +template +struct ArgType<1, T> { enum { TYPE = Arg::CUSTOM }; }; + +template +struct ArgType<1, char[N]> { enum { TYPE = Arg::STRING }; }; + +template +struct ArgType<1, const char[N]> { enum { TYPE = Arg::STRING }; }; + +template <> +struct ArgType<1, const char*> { enum { TYPE = Arg::STRING }; }; + +template <> +struct ArgType<1, std::string> { enum { TYPE = Arg::STRING }; }; + +template <> +struct ArgType<1, fmt::StringRef> { enum { TYPE = Arg::STRING }; }; + +template +struct ArgType<1, wchar_t[N]> { enum { TYPE = Arg::WSTRING }; }; + +template +struct ArgType<1, const wchar_t[N]> { enum { TYPE = Arg::WSTRING }; }; + +template <> +struct ArgType<1, const wchar_t*> { enum { TYPE = Arg::WSTRING }; }; + +template <> +struct ArgType<1, std::wstring> { enum { TYPE = Arg::WSTRING }; }; + +template <> +struct ArgType<1, fmt::WStringRef> { enum { TYPE = Arg::WSTRING }; }; + +#define FMT_ARG_TYPE(Type, CODE) \ + template <> \ + struct ArgType<1, Type> { static const fmt::ULongLong TYPE = Arg::CODE; } + +FMT_ARG_TYPE(None, NONE); +FMT_ARG_TYPE(bool, INT); +FMT_ARG_TYPE(signed char, INT); +FMT_ARG_TYPE(unsigned char, UINT); +FMT_ARG_TYPE(short, INT); +FMT_ARG_TYPE(unsigned short, UINT); +FMT_ARG_TYPE(int, INT); +FMT_ARG_TYPE(unsigned, UINT); +FMT_ARG_TYPE(long, LONG_LONG); // TODO: check sizeof long +FMT_ARG_TYPE(unsigned long, ULONG_LONG); // TODO: check sizeof long +FMT_ARG_TYPE(fmt::LongLong, LONG_LONG); +FMT_ARG_TYPE(fmt::ULongLong, ULONG_LONG); +FMT_ARG_TYPE(char, CHAR); +FMT_ARG_TYPE(wchar_t, CHAR); +FMT_ARG_TYPE(float, DOUBLE); +FMT_ARG_TYPE(double, DOUBLE); +FMT_ARG_TYPE(long double, LONG_DOUBLE); +FMT_ARG_TYPE(void*, POINTER); +// TODO: more types + // Makes an Arg object from any type. template -class MakeArg : public Arg { +class MakeArg : public ArgBase { private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to @@ -661,13 +741,11 @@ class MakeArg : public Arg { MakeArg(T *value); void set_string(StringRef str) { - type = STRING; string.value = str.c_str(); string.size = str.size(); } void set_string(WStringRef str) { - type = WSTRING; CharTraits::convert(wchar_t()); wstring.value = str.c_str(); wstring.size = str.size(); @@ -683,41 +761,34 @@ class MakeArg : public Arg { public: MakeArg() {} - MakeArg(bool value) { type = INT; int_value = value; } - MakeArg(short value) { type = INT; int_value = value; } - MakeArg(unsigned short value) { type = UINT; uint_value = value; } - MakeArg(int value) { type = INT; int_value = value; } - MakeArg(unsigned value) { type = UINT; uint_value = value; } + MakeArg(bool value) { int_value = value; } + MakeArg(short value) { int_value = value; } + MakeArg(unsigned short value) { uint_value = value; } + MakeArg(int value) { int_value = value; } + MakeArg(unsigned value) { uint_value = value; } MakeArg(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. - if (sizeof(long) == sizeof(int)) { - type = INT; + if (sizeof(long) == sizeof(int)) int_value = static_cast(value); - } else { - type = LONG_LONG; + else long_long_value = value; - } } MakeArg(unsigned long value) { - if (sizeof(unsigned long) == sizeof(unsigned)) { - type = UINT; + if (sizeof(unsigned long) == sizeof(unsigned)) uint_value = static_cast(value); - } else { - type = ULONG_LONG; + else ulong_long_value = value; - } } - MakeArg(LongLong value) { type = LONG_LONG; long_long_value = value; } - MakeArg(ULongLong value) { type = ULONG_LONG; ulong_long_value = value; } - MakeArg(float value) { type = DOUBLE; double_value = value; } - MakeArg(double value) { type = DOUBLE; double_value = value; } - MakeArg(long double value) { type = LONG_DOUBLE; long_double_value = value; } - MakeArg(signed char value) { type = CHAR; int_value = value; } - MakeArg(unsigned char value) { type = CHAR; int_value = value; } - MakeArg(char value) { type = CHAR; int_value = value; } + MakeArg(LongLong value) { long_long_value = value; } + MakeArg(ULongLong value) { ulong_long_value = value; } + MakeArg(float value) { double_value = value; } + MakeArg(double value) { double_value = value; } + MakeArg(long double value) { long_double_value = value; } + MakeArg(signed char value) { int_value = value; } + MakeArg(unsigned char value) { int_value = value; } + MakeArg(char value) { int_value = value; } MakeArg(wchar_t value) { - type = CHAR; int_value = internal::CharTraits::convert(value); } @@ -731,12 +802,11 @@ public: MakeArg(const std::wstring &value) { set_string(value); } MakeArg(WStringRef value) { set_string(value); } - MakeArg(void *value) { type = POINTER; pointer_value = value; } - MakeArg(const void *value) { type = POINTER; pointer_value = value; } + MakeArg(void *value) { pointer_value = value; } + MakeArg(const void *value) { pointer_value = value; } template MakeArg(const T &value) { - type = CUSTOM; custom.value = &value; custom.format = &format_custom_arg; } @@ -858,24 +928,34 @@ class ArgFormatter; */ class ArgList { private: - const internal::Arg *args_; - std::size_t size_; + fmt::ULongLong types_; + const internal::ArgBase *args_; public: - ArgList() : size_(0) {} - ArgList(const internal::Arg *args, std::size_t size) - : args_(args), size_(size) {} + // Maximum number of arguments that can be passed in ArgList. + enum { MAX_ARGS = 16 }; - /** - Returns the list size (the number of arguments). - */ - std::size_t size() const { return size_; } + ArgList() : types_(0) {} + ArgList(fmt::ULongLong types, const internal::ArgBase *args) + : types_(types), args_(args) {} /** Returns the argument at specified index. */ - const internal::Arg &operator[](std::size_t index) const { - return args_[index]; + internal::Arg operator[](unsigned index) const { + if (index >= MAX_ARGS) + return internal::Arg(); + fmt::ULongLong shift = index * 4; + using internal::Arg; + Arg::Type type = + static_cast((types_ & (0xfull << shift)) >> shift); + Arg arg; + arg.type = type; + if (type != Arg::NONE) { + internal::ArgBase &base = arg; + base = args_[index]; + } + return arg; } }; @@ -889,7 +969,7 @@ class FormatterBase { int next_arg_index_; // Returns the argument with specified index. - const Arg *do_get_arg(unsigned arg_index, const char *&error); + Arg do_get_arg(unsigned arg_index, const char *&error); protected: void set_args(const ArgList &args) { @@ -898,11 +978,11 @@ class FormatterBase { } // Returns the next argument. - const Arg *next_arg(const char *&error); + Arg next_arg(const char *&error); // Checks if manual indexing is used and returns the argument with // specified index. - const Arg *get_arg(unsigned arg_index, const char *&error); + Arg get_arg(unsigned arg_index, const char *&error); template void write(BasicWriter &w, const Char *start, const Char *end) { @@ -919,7 +999,7 @@ class PrintfFormatter : private FormatterBase { // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. - const Arg &get_arg(const Char *s, + Arg get_arg(const Char *s, unsigned arg_index = (std::numeric_limits::max)()); // Parses argument index, flags and width and returns the argument index. @@ -939,7 +1019,7 @@ class BasicFormatter : private internal::FormatterBase { const Char *start_; // Parses argument index and returns corresponding argument. - const internal::Arg &parse_arg_index(const Char *&s); + internal::Arg parse_arg_index(const Char *&s); public: explicit BasicFormatter(BasicWriter &w) : writer_(w) {} @@ -1188,31 +1268,58 @@ inline StrFormatSpec pad( # define FMT_GEN15(f) FMT_GEN14(f), f(14) # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n +# define FMT_MAKE_ARG_TYPE(n) T##n # define FMT_MAKE_ARG(n) const T##n &v##n # define FMT_MAKE_REF_char(n) fmt::internal::MakeArg(v##n) # define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeArg(v##n) +/*namespace internal { +#undef FMT_ARG_TYPE +#define FMT_ARG_TYPE(n, m) \ + template \ + struct ArgType##n { \ + enum { TYPE = (ArgType1::TYPE << 4 * m) | \ + ArgType##m::TYPE }; \ + } +FMT_ARG_TYPE(2, 1); +FMT_ARG_TYPE(3, 2); +FMT_ARG_TYPE(4, 3); +FMT_ARG_TYPE(5, 4); +FMT_ARG_TYPE(6, 5); +FMT_ARG_TYPE(7, 6); +FMT_ARG_TYPE(8, 7); +FMT_ARG_TYPE(9, 8); +FMT_ARG_TYPE(10, 9); +FMT_ARG_TYPE(11, 10); +FMT_ARG_TYPE(12, 11); +FMT_ARG_TYPE(13, 12); +FMT_ARG_TYPE(14, 13); +FMT_ARG_TYPE(15, 14); +}*/ + #if FMT_USE_VARIADIC_TEMPLATES // Defines a variadic function returning void. # define FMT_VARIADIC_VOID(func, arg_type) \ template \ void func(arg_type arg1, const Args & ... args) { \ - using fmt::internal::Arg; \ - const Arg arg_array[fmt::internal::NonZero::VALUE] = { \ + const fmt::internal::ArgBase arg_array[ \ + fmt::internal::NonZero::VALUE] = { \ fmt::internal::MakeArg(args)... \ }; \ - func(arg1, ArgList(arg_array, sizeof...(Args))); \ + func(arg1, ArgList( \ + internal::ArgType<15, Args...>::TYPE, arg_array)); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - using fmt::internal::Arg; \ - const Arg arg_array[fmt::internal::NonZero::VALUE] = { \ + const fmt::internal::ArgBase arg_array[ \ + fmt::internal::NonZero::VALUE] = { \ fmt::internal::MakeArg(args)... \ }; \ - func(arg0, arg1, ArgList(arg_array, sizeof...(Args))); \ + func(arg0, arg1, ArgList( \ + internal::ArgType<15, Args...>::TYPE, arg_array)); \ } #else @@ -1223,8 +1330,9 @@ inline StrFormatSpec pad( # define FMT_WRAP1(func, arg_type, n) \ template \ inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Arg args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + const fmt::internal::ArgBase args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg1, fmt::ArgList( \ + fmt::internal::ArgType::TYPE, args)); \ } // Emulates a variadic function returning void on a pre-C++11 compiler. @@ -1238,8 +1346,9 @@ inline StrFormatSpec pad( # define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ template \ ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Arg args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + const fmt::internal::ArgBase args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg0, arg1, fmt::ArgList( \ + internal::ArgType::TYPE, args)); \ } // Emulates a variadic constructor on a pre-C++11 compiler. @@ -1912,7 +2021,11 @@ template void format(BasicFormatter &f, const Char *&format_str, const T &value) { std::basic_ostringstream os; os << value; - format_str = f.format(format_str, internal::MakeArg(os.str())); + internal::Arg arg; + internal::ArgBase &base = arg; + base = internal::MakeArg(os.str()); + arg.type = internal::Arg::STRING; + format_str = f.format(format_str, arg); } // Reports a system error without throwing an exception. @@ -2195,12 +2308,12 @@ inline void format_decimal(char *&buffer, T value) { template \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ - using fmt::internal::Arg; \ - const Arg array[fmt::internal::NonZero::VALUE] = { \ + using fmt::internal::ArgBase; \ + const ArgBase array[fmt::internal::NonZero::VALUE] = { \ fmt::internal::MakeArg(args)... \ }; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(array, sizeof...(Args))); \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::ArgType<15, Args...>::TYPE, array)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments @@ -2209,9 +2322,9 @@ inline void format_decimal(char *&buffer, T value) { template \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Arg args[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + const fmt::internal::ArgBase args[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::ArgType::TYPE, args)); \ } # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ diff --git a/test/macro-test.cc b/test/macro-test.cc index 2964177a..e25908ba 100644 --- a/test/macro-test.cc +++ b/test/macro-test.cc @@ -67,7 +67,7 @@ int result; #define MAKE_TEST(func) \ void func(const char *format, const fmt::ArgList &args) { \ result = 0; \ - for (std::size_t i = 0, n = args.size(); i < n; ++i) \ + for (unsigned i = 0; args[i].type; ++i) \ result += args[i].int_value; \ } @@ -98,7 +98,7 @@ struct S {}; int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \ int result = 0; \ - for (std::size_t i = 0, n = args.size(); i < n; ++i) \ + for (std::size_t i = 0; args[i].type; ++i) \ result += args[i].int_value; \ return result; } diff --git a/test/util-test.cc b/test/util-test.cc index d3872130..d63a244a 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -42,8 +42,8 @@ #undef max using fmt::StringRef; +using fmt::internal::ArgBase; using fmt::internal::Arg; -using fmt::internal::MakeArg; namespace { @@ -52,6 +52,16 @@ template std::basic_ostream &operator<<(std::basic_ostream &os, Test) { return os << "test"; } + +template +Arg make_arg(const T &value) { + Arg arg = Arg(); + ArgBase &base = arg; + base = fmt::internal::MakeArg(value); + arg.type = static_cast(fmt::internal::ArgType<1, T>::TYPE); + return arg; +} + } // namespace TEST(UtilTest, Increment) { @@ -74,7 +84,7 @@ struct ArgInfo; #define ARG_INFO(type_code, Type, field) \ template <> \ struct ArgInfo { \ - static Type get(const Arg &arg) { return arg.field; } \ + static Type get(const ArgBase &arg) { return arg.field; } \ }; ARG_INFO(INT, int, int_value); @@ -90,7 +100,7 @@ ARG_INFO(POINTER, const void *, pointer_value); ARG_INFO(CUSTOM, Arg::CustomValue, custom); #define CHECK_ARG_INFO(Type, field, value) { \ - Arg arg = {Arg::Type}; \ + ArgBase arg = {}; \ arg.field = value; \ EXPECT_EQ(value, ArgInfo::get(arg)); \ } @@ -109,14 +119,14 @@ TEST(ArgTest, ArgInfo) { CHECK_ARG_INFO(WSTRING, wstring.value, WSTR); int p = 0; CHECK_ARG_INFO(POINTER, pointer_value, &p); - Arg arg = {Arg::CUSTOM}; + ArgBase arg = {}; arg.custom.value = &p; EXPECT_EQ(&p, ArgInfo::get(arg).value); } #define EXPECT_ARG_(Char, type_code, MakeArgType, ExpectedType, value) { \ MakeArgType input = static_cast(value); \ - Arg arg = MakeArg(input); \ + Arg arg = make_arg(input); \ EXPECT_EQ(Arg::type_code, arg.type); \ ExpectedType expected_value = static_cast(value); \ EXPECT_EQ(expected_value, ArgInfo::get(arg)); \ @@ -221,7 +231,7 @@ TEST(ArgTest, MakeArg) { EXPECT_ARG(POINTER, const void*, &n); ::Test t; - fmt::internal::Arg arg = MakeArg(t); + Arg arg = make_arg(t); EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); EXPECT_EQ(&t, arg.custom.value); fmt::Writer w; @@ -232,13 +242,13 @@ TEST(ArgTest, MakeArg) { } struct Result { - fmt::internal::Arg arg; + Arg arg; - Result() : arg(MakeArg(0xdeadbeef)) {} + Result() : arg(make_arg(0xdeadbeef)) {} template - Result(const T& value) : arg(MakeArg(value)) {} - Result(const wchar_t *s) : arg(MakeArg(s)) {} + Result(const T& value) : arg(make_arg(value)) {} + Result(const wchar_t *s) : arg(make_arg(s)) {} }; struct TestVisitor : fmt::internal::ArgVisitor { @@ -258,7 +268,8 @@ struct TestVisitor : fmt::internal::ArgVisitor { }; #define EXPECT_RESULT_(Char, type_code, value) { \ - Result result = TestVisitor().visit(MakeArg(value)); \ + Arg arg = make_arg(value); \ + Result result = TestVisitor().visit(arg); \ EXPECT_EQ(Arg::type_code, result.arg.type); \ EXPECT_EQ(value, ArgInfo::get(result.arg)); \ } @@ -283,7 +294,7 @@ TEST(ArgVisitorTest, VisitAll) { const void *p = STR; EXPECT_RESULT(POINTER, p); ::Test t; - Result result = TestVisitor().visit(MakeArg(t)); + Result result = TestVisitor().visit(make_arg(t)); EXPECT_EQ(Arg::CUSTOM, result.arg.type); EXPECT_EQ(&t, result.arg.custom.value); } @@ -298,7 +309,7 @@ struct TestAnyVisitor : fmt::internal::ArgVisitor { #undef EXPECT_RESULT #define EXPECT_RESULT(type_code, value) { \ - Result result = TestAnyVisitor().visit(MakeArg(value)); \ + Result result = TestAnyVisitor().visit(make_arg(value)); \ EXPECT_EQ(Arg::type_code, result.arg.type); \ EXPECT_EQ(value, ArgInfo::get(result.arg)); \ } @@ -318,7 +329,7 @@ struct TestUnhandledVisitor : }; #define EXPECT_UNHANDLED(value) \ - EXPECT_STREQ("test", TestUnhandledVisitor().visit(MakeArg(value))); + EXPECT_STREQ("test", TestUnhandledVisitor().visit(make_arg(value))); TEST(ArgVisitorTest, VisitUnhandledArg) { EXPECT_UNHANDLED(42); @@ -338,7 +349,8 @@ TEST(ArgVisitorTest, VisitUnhandledArg) { } TEST(ArgVisitorTest, VisitInvalidArg) { - Arg arg = {static_cast(Arg::CUSTOM + 1)}; + Arg arg = Arg(); + arg.type = static_cast(Arg::CUSTOM + 1); EXPECT_DEBUG_DEATH(TestVisitor().visit(arg), "Assertion"); }