Add constexpr values to lambda to handle msvc issue with respect to captured constexpr values

This commit is contained in:
ado 2023-07-29 01:11:29 +02:00
parent 75f5ee2a55
commit 705ce422f0

View File

@ -20,18 +20,15 @@ struct unique_file_name {
const std::string name; const std::string name;
unique_file_name() unique_file_name()
: name{"random_" + std::to_string(i++) + time_now_rand() + : name{"random_" + std::to_string(i++) + time_now_rand() + "_file.csv"} {}
"_file.csv"} {
}
~unique_file_name() { ~unique_file_name() { std::filesystem::remove(name); }
std::filesystem::remove(name);
}
}; };
void replace_all(std::string& s, const std::string& from, void replace_all(std::string &s, const std::string &from,
const std::string& to) { const std::string &to) {
if (from.empty()) return; if (from.empty())
return;
size_t start_pos = 0; size_t start_pos = 0;
while ((start_pos = s.find(from, start_pos)) != std::string::npos) { while ((start_pos = s.find(from, start_pos)) != std::string::npos) {
s.replace(start_pos, from.length(), to); s.replace(start_pos, from.length(), to);
@ -39,7 +36,7 @@ void replace_all(std::string& s, const std::string& from,
} }
} }
void update_if_crlf(std::string& s) { void update_if_crlf(std::string &s) {
#ifdef _WIN32 #ifdef _WIN32
replace_all(s, "\r\n", "\n"); replace_all(s, "\r\n", "\n");
#else #else
@ -65,30 +62,28 @@ struct X {
.append(delim) .append(delim)
.append(s); .append(s);
} }
auto tied() const { auto tied() const { return std::tie(i, d, s); }
return std::tie(i, d, s);
}
}; };
template <typename T> template <typename T>
std::enable_if_t<ss::has_m_tied_t<T>, bool> operator==(const T& lhs, std::enable_if_t<ss::has_m_tied_t<T>, bool> operator==(const T &lhs,
const T& rhs) { const T &rhs) {
return lhs.tied() == rhs.tied(); return lhs.tied() == rhs.tied();
} }
template <typename T> template <typename T>
static void make_and_write(const std::string& file_name, static void make_and_write(const std::string &file_name,
const std::vector<T>& data, const std::vector<T> &data,
const std::vector<std::string>& header = {}) { const std::vector<std::string> &header = {}) {
std::ofstream out{file_name}; std::ofstream out{file_name};
#ifdef _WIN32 #ifdef _WIN32
std::vector<const char*> new_lines = {"\n"}; std::vector<const char *> new_lines = {"\n"};
#else #else
std::vector<const char*> new_lines = {"\n", "\r\n"}; std::vector<const char *> new_lines = {"\n", "\r\n"};
#endif #endif
for (const auto& i : header) { for (const auto &i : header) {
if (&i != &header.front()) { if (&i != &header.front()) {
out << T::delim; out << T::delim;
} }
@ -125,7 +120,7 @@ TEST_CASE("parser test various cases") {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
for (const auto& a : p2.iterate<int, double, std::string>()) { for (const auto &a : p2.iterate<int, double, std::string>()) {
i2.emplace_back(ss::to_object<X>(a)); i2.emplace_back(ss::to_object<X>(a));
} }
@ -153,7 +148,7 @@ TEST_CASE("parser test various cases") {
} }
p2.ignore_next(); p2.ignore_next();
for (const auto& a : p2.iterate<tup>()) { for (const auto &a : p2.iterate<tup>()) {
i2.emplace_back(ss::to_object<X>(a)); i2.emplace_back(ss::to_object<X>(a));
} }
@ -178,7 +173,7 @@ TEST_CASE("parser test various cases") {
i.push_back(p.get_object<X, int, double, std::string>()); i.push_back(p.get_object<X, int, double, std::string>());
} }
for (auto&& a : p2.iterate_object<X, int, double, std::string>()) { for (auto &&a : p2.iterate_object<X, int, double, std::string>()) {
i2.push_back(std::move(a)); i2.push_back(std::move(a));
} }
@ -190,7 +185,7 @@ TEST_CASE("parser test various cases") {
ss::parser p{f.name, ","}; ss::parser p{f.name, ","};
std::vector<X> i; std::vector<X> i;
for (auto&& a : p.iterate_object<X, int, double, std::string>()) { for (auto &&a : p.iterate_object<X, int, double, std::string>()) {
i.push_back(std::move(a)); i.push_back(std::move(a));
} }
@ -223,7 +218,7 @@ TEST_CASE("parser test various cases") {
std::vector<X> i; std::vector<X> i;
using tup = std::tuple<int, double, std::string>; using tup = std::tuple<int, double, std::string>;
for (auto&& a : p.iterate_object<X, tup>()) { for (auto &&a : p.iterate_object<X, tup>()) {
i.push_back(std::move(a)); i.push_back(std::move(a));
} }
@ -245,7 +240,7 @@ TEST_CASE("parser test various cases") {
ss::parser p{f.name, ","}; ss::parser p{f.name, ","};
std::vector<X> i; std::vector<X> i;
for (auto&& a : p.iterate<X>()) { for (auto &&a : p.iterate<X>()) {
i.push_back(std::move(a)); i.push_back(std::move(a));
} }
@ -261,29 +256,28 @@ TEST_CASE("parser test various cases") {
std::vector<X> i2; std::vector<X> i2;
while (!p.eof()) { while (!p.eof()) {
auto a = auto a = p.get_object<X, ss::ax<int, excluded>, double, std::string>();
p.get_object<X, ss::ax<int, excluded>, double, std::string>();
if (p.valid()) { if (p.valid()) {
i.push_back(a); i.push_back(a);
} }
} }
for (auto&& a : p2.iterate_object<X, ss::ax<int, excluded>, double, for (auto &&a :
std::string>()) { p2.iterate_object<X, ss::ax<int, excluded>, double, std::string>()) {
if (p2.valid()) { if (p2.valid()) {
i2.push_back(std::move(a)); i2.push_back(std::move(a));
} }
} }
std::vector<X> expected; std::vector<X> expected;
for (auto& x : data) { for (auto &x : data) {
if (x.i != excluded) { if (x.i != excluded) {
expected.push_back(x); expected.push_back(x);
} }
} }
std::copy_if(data.begin(), data.end(), expected.begin(), std::copy_if(data.begin(), data.end(), expected.begin(),
[](const X& x) { return x.i != excluded; }); [&](const X &x) { return x.i != excluded; });
CHECK_EQ(i, expected); CHECK_EQ(i, expected);
CHECK_EQ(i2, expected); CHECK_EQ(i2, expected);
} }
@ -302,7 +296,7 @@ TEST_CASE("parser test various cases") {
} }
} }
for (auto&& a : for (auto &&a :
p2.iterate_object<X, ss::nx<int, 3>, double, std::string>()) { p2.iterate_object<X, ss::nx<int, 3>, double, std::string>()) {
if (p2.valid()) { if (p2.valid()) {
i2.push_back(std::move(a)); i2.push_back(std::move(a));
@ -330,7 +324,7 @@ TEST_CASE("parser test various cases") {
i.push_back(p.get_next<X>()); i.push_back(p.get_next<X>());
} }
for (auto&& a : p2.iterate<X>()) { for (auto &&a : p2.iterate<X>()) {
i2.push_back(std::move(a)); i2.push_back(std::move(a));
} }
@ -344,20 +338,17 @@ struct test_struct {
int i; int i;
double d; double d;
char c; char c;
auto tied() { auto tied() { return std::tie(i, d, c); }
return std::tie(i, d, c);
}
}; };
void expect_test_struct(const test_struct&) { void expect_test_struct(const test_struct &) {}
}
// various scenarios // various scenarios
TEST_CASE("parser test composite conversion") { TEST_CASE("parser test composite conversion") {
unique_file_name f; unique_file_name f;
{ {
std::ofstream out{f.name}; std::ofstream out{f.name};
for (auto& i : for (auto &i :
{"10,a,11.1", "10,20,11.1", "junk", "10,11.1", "1,11.1,a", "junk", {"10,a,11.1", "10,20,11.1", "junk", "10,11.1", "1,11.1,a", "junk",
"10,junk", "11,junk", "10,11.1,c", "10,20", "10,22.2,f"}) { "10,junk", "11,junk", "10,11.1,c", "10,20", "10,22.2,f"}) {
out << i << std::endl; out << i << std::endl;
@ -374,11 +365,11 @@ TEST_CASE("parser test composite conversion") {
{ {
constexpr static auto expectedData = std::tuple{10, 'a', 11.1}; constexpr static auto expectedData = std::tuple{10, 'a', 11.1};
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] = p.try_next<int, int, double>(fail)
p.try_next<int, int, double>(fail)
.or_else<test_struct>(fail) .or_else<test_struct>(fail)
.or_else<int, char, double>( .or_else<int, char, double>([&](auto &&data) {
[](auto&& data) { CHECK_EQ(data, expectedData); }) CHECK_EQ(data, expectedData);
})
.on_error(fail) .on_error(fail)
.or_else<test_tuple>(fail) .or_else<test_tuple>(fail)
.values(); .values();
@ -396,7 +387,7 @@ TEST_CASE("parser test composite conversion") {
constexpr static auto expectedData = std::tuple{10, 20, 11.1}; constexpr static auto expectedData = std::tuple{10, 20, 11.1};
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] =
p.try_next<int, int, double>([](auto& i1, auto i2, double d) { p.try_next<int, int, double>([&](auto &i1, auto i2, double d) {
CHECK_EQ(std::tie(i1, i2, d), expectedData); CHECK_EQ(std::tie(i1, i2, d), expectedData);
}) })
.on_error(fail) .on_error(fail)
@ -438,11 +429,10 @@ TEST_CASE("parser test composite conversion") {
{ {
REQUIRE(!p.eof()); REQUIRE(!p.eof());
auto [d1, d2] = auto [d1, d2] = p.try_next<int, double>([](auto &i, auto &d) {
p.try_next<int, double>([](auto& i, auto& d) {
REQUIRE_EQ(std::tie(i, d), std::tuple{10, 11.1}); REQUIRE_EQ(std::tie(i, d), std::tuple{10, 11.1});
}) })
.or_else<int, double>([](auto&, auto&) { FAIL(""); }) .or_else<int, double>([](auto &, auto &) { FAIL(""); })
.values(); .values();
REQUIRE(p.valid()); REQUIRE(p.valid());
@ -453,7 +443,7 @@ TEST_CASE("parser test composite conversion") {
{ {
REQUIRE(!p.eof()); REQUIRE(!p.eof());
auto [d1, d2] = p.try_next<int, double>([](auto&, auto&) { FAIL(""); }) auto [d1, d2] = p.try_next<int, double>([](auto &, auto &) { FAIL(""); })
.or_else<test_struct>(expect_test_struct) .or_else<test_struct>(expect_test_struct)
.values(); .values();
@ -466,8 +456,7 @@ TEST_CASE("parser test composite conversion") {
{ {
REQUIRE(!p.eof()); REQUIRE(!p.eof());
auto [d1, d2, d3, d4, d5] = auto [d1, d2, d3, d4, d5] = p.try_next<int, int, double>(fail)
p.try_next<int, int, double>(fail)
.or_object<test_struct, int, double, char>() .or_object<test_struct, int, double, char>()
.or_else<test_struct>(expect_test_struct) .or_else<test_struct>(expect_test_struct)
.or_else<test_tuple>(fail) .or_else<test_tuple>(fail)
@ -530,7 +519,7 @@ TEST_CASE("parser test composite conversion") {
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] =
p.try_next<int, int>([] { return false; }) p.try_next<int, int>([] { return false; })
.or_else<int, double>([](auto&) { return false; }) .or_else<int, double>([](auto &) { return false; })
.or_else<int, int>() .or_else<int, int>()
.or_else<int, int>(fail) .or_else<int, int>(fail)
.values(); .values();
@ -548,7 +537,7 @@ TEST_CASE("parser test composite conversion") {
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] =
p.try_object<test_struct, int, double, char>([] { return false; }) p.try_object<test_struct, int, double, char>([] { return false; })
.or_else<int, double>([](auto&) { return false; }) .or_else<int, double>([](auto &) { return false; })
.or_object<test_struct, int, double, char>() .or_object<test_struct, int, double, char>()
.or_else<int, int>(fail) .or_else<int, int>(fail)
.values(); .values();
@ -567,24 +556,22 @@ TEST_CASE("parser test composite conversion") {
size_t move_called = 0; size_t move_called = 0;
struct my_string { struct my_string {
char* data{nullptr}; char *data{nullptr};
my_string() = default; my_string() = default;
~my_string() { ~my_string() { delete[] data; }
delete[] data;
}
// make sure no object is copied // make sure no object is copied
my_string(const my_string&) = delete; my_string(const my_string &) = delete;
my_string& operator=(const my_string&) = delete; my_string &operator=(const my_string &) = delete;
my_string(my_string&& other) : data{other.data} { my_string(my_string &&other) : data{other.data} {
move_called++; move_called++;
other.data = nullptr; other.data = nullptr;
} }
my_string& operator=(my_string&& other) { my_string &operator=(my_string &&other) {
move_called++; move_called++;
data = other.data; data = other.data;
return *this; return *this;
@ -592,7 +579,7 @@ struct my_string {
}; };
template <> template <>
inline bool ss::extract(const char* begin, const char* end, my_string& s) { inline bool ss::extract(const char *begin, const char *end, my_string &s) {
size_t size = end - begin; size_t size = end - begin;
s.data = new char[size + 1]; s.data = new char[size + 1];
strncpy(s.data, begin, size); strncpy(s.data, begin, size);
@ -604,9 +591,7 @@ struct xyz {
my_string x; my_string x;
my_string y; my_string y;
my_string z; my_string z;
auto tied() { auto tied() { return std::tie(x, y, z); }
return std::tie(x, y, z);
}
}; };
TEST_CASE("parser test the moving of parsed values") { TEST_CASE("parser test the moving of parsed values") {
@ -657,12 +642,12 @@ TEST_CASE("parser test the moving of parsed composite values") {
return; return;
ss::parser p{"", ""}; ss::parser p{"", ""};
p.try_next<my_string, my_string, my_string>() p.try_next<my_string, my_string, my_string>()
.or_else<my_string, my_string, my_string, my_string>([](auto&&) {}) .or_else<my_string, my_string, my_string, my_string>([](auto &&) {})
.or_else<my_string>([](auto&) {}) .or_else<my_string>([](auto &) {})
.or_else<xyz>([](auto&&) {}) .or_else<xyz>([](auto &&) {})
.or_object<xyz, my_string, my_string, my_string>([](auto&&) {}) .or_object<xyz, my_string, my_string, my_string>([](auto &&) {})
.or_else<std::tuple<my_string, my_string, my_string>>( .or_else<std::tuple<my_string, my_string, my_string>>(
[](auto&, auto&, auto&) {}); [](auto &, auto &, auto &) {});
} }
TEST_CASE("parser test error mode") { TEST_CASE("parser test error mode") {
@ -681,7 +666,7 @@ TEST_CASE("parser test error mode") {
CHECK_FALSE(p.error_msg().empty()); CHECK_FALSE(p.error_msg().empty());
} }
std::string no_quote(const std::string& s) { std::string no_quote(const std::string &s) {
if (!s.empty() && s[0] == '"') { if (!s.empty() && s[0] == '"') {
return {std::next(begin(s)), std::prev(end(s))}; return {std::next(begin(s)), std::prev(end(s))};
} }
@ -696,12 +681,12 @@ TEST_CASE("parser test csv on multiple lines with quotes") {
{7, 8, "\"u\"\"\""}, {7, 8, "\"u\"\"\""},
{9, 10, "v"}, {9, 10, "v"},
{11, 12, "\"w\n\""}}; {11, 12, "\"w\n\""}};
for (auto& [_, __, s] : data) { for (auto &[_, __, s] : data) {
update_if_crlf(s); update_if_crlf(s);
} }
make_and_write(f.name, data); make_and_write(f.name, data);
for (auto& [_, __, s] : data) { for (auto &[_, __, s] : data) {
s = no_quote(s); s = no_quote(s);
if (s[0] == 'u') { if (s[0] == 'u') {
s = "u\""; s = "u\"";
@ -716,7 +701,7 @@ TEST_CASE("parser test csv on multiple lines with quotes") {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
for (auto& [_, __, s] : i) { for (auto &[_, __, s] : i) {
update_if_crlf(s); update_if_crlf(s);
} }
CHECK_EQ(i, data); CHECK_EQ(i, data);
@ -728,25 +713,22 @@ TEST_CASE("parser test csv on multiple lines with quotes") {
} }
} }
std::string no_escape(std::string& s) { std::string no_escape(std::string &s) {
s.erase(std::remove(begin(s), end(s), '\\'), end(s)); s.erase(std::remove(begin(s), end(s), '\\'), end(s));
return s; return s;
} }
TEST_CASE("parser test csv on multiple lines with escapes") { TEST_CASE("parser test csv on multiple lines with escapes") {
unique_file_name f; unique_file_name f;
std::vector<X> data = {{1, 2, "x\\\nx\\\r\nx"}, std::vector<X> data = {
{5, 6, "z\\\nz\\\nz"}, {1, 2, "x\\\nx\\\r\nx"}, {5, 6, "z\\\nz\\\nz"}, {7, 8, "u"},
{7, 8, "u"}, {3, 4, "y\\\ny\\\ny"}, {9, 10, "v\\\\"}, {11, 12, "w\\\n"}};
{3, 4, "y\\\ny\\\ny"}, for (auto &[_, __, s] : data) {
{9, 10, "v\\\\"},
{11, 12, "w\\\n"}};
for (auto& [_, __, s] : data) {
update_if_crlf(s); update_if_crlf(s);
} }
make_and_write(f.name, data); make_and_write(f.name, data);
for (auto& [_, __, s] : data) { for (auto &[_, __, s] : data) {
s = no_escape(s); s = no_escape(s);
if (s == "v") { if (s == "v") {
s = "v\\"; s = "v\\";
@ -761,7 +743,7 @@ TEST_CASE("parser test csv on multiple lines with escapes") {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
for (auto& [_, __, s] : i) { for (auto &[_, __, s] : i) {
update_if_crlf(s); update_if_crlf(s);
} }
CHECK_EQ(i, data); CHECK_EQ(i, data);
@ -807,7 +789,7 @@ TEST_CASE("parser test csv on multiple lines with quotes and escapes") {
#endif #endif
{9, 10, "just strings"}}; {9, 10, "just strings"}};
for (auto& [_, __, s] : i) { for (auto &[_, __, s] : i) {
update_if_crlf(s); update_if_crlf(s);
} }
CHECK_EQ(i, data); CHECK_EQ(i, data);
@ -833,8 +815,8 @@ TEST_CASE("parser test multiline restricted") {
out << "19,20,just strings" << std::endl; out << "19,20,just strings" << std::endl;
} }
ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>> ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>> p{
p{f.name, ","}; f.name, ","};
std::vector<X> i; std::vector<X> i;
while (!p.eof()) { while (!p.eof()) {
@ -853,26 +835,23 @@ TEST_CASE("parser test multiline restricted") {
{9, 10, "just\n\nstrings"}, {9, 10, "just\n\nstrings"},
{19, 20, "just strings"}}; {19, 20, "just strings"}};
for (auto& [_, __, s] : i) { for (auto &[_, __, s] : i) {
update_if_crlf(s); update_if_crlf(s);
} }
CHECK_EQ(i, data); CHECK_EQ(i, data);
} }
template <typename T, typename Tuple> template <typename T, typename Tuple> struct has_type;
struct has_type;
template <typename T, typename... Us> template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>> struct has_type<T, std::tuple<Us...>>
: std::disjunction<std::is_same<T, Us>...> {}; : std::disjunction<std::is_same<T, Us>...> {};
void checkSize(size_t size1, size_t size2) { void checkSize(size_t size1, size_t size2) { CHECK_EQ(size1, size2); }
CHECK_EQ(size1, size2);
}
template <typename... Ts> template <typename... Ts>
void testFields(const std::string file_name, const std::vector<X>& data, void testFields(const std::string file_name, const std::vector<X> &data,
const std::vector<std::string>& fields) { const std::vector<std::string> &fields) {
using CaseType = std::tuple<Ts...>; using CaseType = std::tuple<Ts...>;
ss::parser p{file_name, ","}; ss::parser p{file_name, ","};
@ -880,7 +859,7 @@ void testFields(const std::string file_name, const std::vector<X>& data,
p.use_fields(fields); p.use_fields(fields);
std::vector<CaseType> i; std::vector<CaseType> i;
for (const auto& a : p.iterate<CaseType>()) { for (const auto &a : p.iterate<CaseType>()) {
i.push_back(a); i.push_back(a);
} }
@ -911,14 +890,14 @@ TEST_CASE("parser test various cases with header") {
{7, 8, "u"}, {9, 10, "v"}, {11, 12, "w"}}; {7, 8, "u"}, {9, 10, "v"}, {11, 12, "w"}};
make_and_write(f.name, data, header); make_and_write(f.name, data, header);
const auto& o = f.name; const auto &o = f.name;
const auto& d = data; const auto &d = data;
{ {
ss::parser<ss::string_error> p{f.name, ","}; ss::parser<ss::string_error> p{f.name, ","};
std::vector<X> i; std::vector<X> i;
for (const auto& a : p.iterate<int, double, std::string>()) { for (const auto &a : p.iterate<int, double, std::string>()) {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
@ -930,7 +909,7 @@ TEST_CASE("parser test various cases with header") {
std::vector<X> i; std::vector<X> i;
p.ignore_next(); p.ignore_next();
for (const auto& a : p.iterate<int, double, std::string>()) { for (const auto &a : p.iterate<int, double, std::string>()) {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
@ -941,7 +920,7 @@ TEST_CASE("parser test various cases with header") {
ss::parser<ss::ignore_header> p{f.name, ","}; ss::parser<ss::ignore_header> p{f.name, ","};
std::vector<X> i; std::vector<X> i;
for (const auto& a : p.iterate<int, double, std::string>()) { for (const auto &a : p.iterate<int, double, std::string>()) {
i.emplace_back(ss::to_object<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
@ -996,8 +975,7 @@ TEST_CASE("parser test various cases with header") {
p.use_fields(Str, Int, Dbl); p.use_fields(Str, Int, Dbl);
{ {
auto [string_, int_, double_] = auto [string_, int_, double_] = p.get_next<std::string, int, double>();
p.get_next<std::string, int, double>();
CHECK_EQ(double_, data[3].d); CHECK_EQ(double_, data[3].d);
CHECK_EQ(int_, data[3].i); CHECK_EQ(int_, data[3].i);
CHECK_EQ(string_, data[3].s); CHECK_EQ(string_, data[3].s);
@ -1044,12 +1022,12 @@ TEST_CASE("parser test various cases with header") {
testFields<double, int, str>(o, d, {Dbl, Int, Str}); testFields<double, int, str>(o, d, {Dbl, Int, Str});
} }
void testIgnoreEmpty(const std::vector<X>& data) { void testIgnoreEmpty(const std::vector<X> &data) {
unique_file_name f; unique_file_name f;
make_and_write(f.name, data); make_and_write(f.name, data);
std::vector<X> expected; std::vector<X> expected;
for (const auto& d : data) { for (const auto &d : data) {
if (d.s != X::make_empty) { if (d.s != X::make_empty) {
expected.push_back(d); expected.push_back(d);
} }
@ -1059,7 +1037,7 @@ void testIgnoreEmpty(const std::vector<X>& data) {
ss::parser<ss::string_error, ss::ignore_empty> p{f.name, ","}; ss::parser<ss::string_error, ss::ignore_empty> p{f.name, ","};
std::vector<X> i; std::vector<X> i;
for (const auto& a : p.iterate<X>()) { for (const auto &a : p.iterate<X>()) {
i.push_back(a); i.push_back(a);
} }
@ -1070,7 +1048,7 @@ void testIgnoreEmpty(const std::vector<X>& data) {
ss::parser<ss::string_error> p{f.name, ","}; ss::parser<ss::string_error> p{f.name, ","};
std::vector<X> i; std::vector<X> i;
size_t n = 0; size_t n = 0;
for (const auto& a : p.iterate<X>()) { for (const auto &a : p.iterate<X>()) {
if (data.at(n).s == X::make_empty) { if (data.at(n).s == X::make_empty) {
CHECK_FALSE(p.valid()); CHECK_FALSE(p.valid());
} }