-
Dear all How to tackle a variant type as in the title? I tried various contracts such as this one: using Variant = std::variant<int, float, bool, std::string>;
namespace daw::json {
template <> struct json_data_contract<Variant> {
using type = json_type_alias<
json_variant_no_name<Variant, json_variant_type_list<int, json_number_no_name<float>, bool, json_string_no_name<>>>>;
static constexpr auto to_json_data (Variant const &value) { return value; }
};
} // namespace daw::json and to my despair it parses either ints or floats, but not both (the last line throws from the JSON lib):
Thanks PS. I know I can remove |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 4 replies
-
If this is representative and there is no tag member to dispatch with, then I would look into struct FooConstructor {
|
Beta Was this translation helpful? Give feedback.
-
I will add a better error in that case, on further thought, what is going on is you have tried to map 2 number types and it is taking the first one. So it parsed the integer part of 67.8 and then when it was trying to move to the next value it ran into a |
Beta Was this translation helpful? Give feedback.
-
Thanks to your suggestion I'm able to parse my variant, but I can't serialize it now :( Let me paste my whole "unit test" : #include <catch2/catch_test_macros.hpp>
#include <daw/json/daw_json_link.h>
#include <string>
namespace my {
using Var2 = std::variant<int, float, std::string>;
struct Var2Constructor {
Var2 operator() () const { return Var2{}; }
Var2 operator() (char const *ptr, std::size_t sz) const
{
using namespace daw::json;
auto jv = daw::json::json_value (ptr, sz);
try {
auto foo = as<int> (jv);
return {foo};
}
catch (...) {
}
try {
auto foo = as<float> (jv);
return {foo};
}
catch (...) {
}
try {
auto foo = as<bool> (jv);
return {foo};
}
catch (...) {
}
return std::string{ptr, sz};
}
};
} // namespace my
namespace daw::json {
template <> struct json_data_contract<my::Var2> {
using type = json_type_alias<json_raw_no_name<my::Var2, my::Var2Constructor>>;
static constexpr auto to_json_data (my::Var2 const &value) { return value; }
};
} // namespace daw::json
TEST_CASE ("variant 2 numbers", "[json]")
{
using namespace daw::json;
{
auto kx = from_json<my::Var2> (R"(67)");
CHECK (std::get<int> (kx) == 67);
}
{
auto kx = from_json<my::Var2> (R"(67.8)");
CHECK (std::get<float> (kx) == 67.8F);
}
{
auto kx = from_json<my::Var2> (R"("test")");
CHECK (std::get<std::string> (kx) == "test");
}
my::Var2 v = 1;
CHECK (to_json<my::Var2> (v) == "1");
} It complaints about not finding correct overload of utils::copy_to_iterator:
and
This second one is probably because my type (the variant itself) is not |
Beta Was this translation helpful? Give feedback.
-
You will want something like #include <catch2/catch_test_macros.hpp>
#include <daw/json/daw_json_link.h>
#include <string>
namespace my {
using Var2 = std::variant<int, float, std::string>;
struct Var2Constructor {
Var2 operator() () const { return Var2{}; }
Var2 operator() (char const *ptr, std::size_t sz) const
{
using namespace daw::json;
auto jv = daw::json::json_value (ptr, sz);
try {
auto foo = as<int> (jv);
return {foo};
}
catch (...) {
}
try {
auto foo = as<float> (jv);
return {foo};
}
catch (...) {
}
try {
auto foo = as<bool> (jv);
return {foo};
}
catch (...) {
}
return std::string{ptr, sz};
}
};
} // namespace my
namespace daw::json {
template <> struct json_data_contract<my::Var2> {
using type = json_type_alias<json_raw_no_name<my::Var2, my::Var2Constructor>>;
static auto to_json_data (my::Var2 const &value) {
return std::visit( []( auto const & alt ) { return to_json( alt ); }, value );
}
};
} // namespace daw::json
TEST_CASE ("variant 2 numbers", "[json]")
{
using namespace daw::json;
{
auto kx = from_json<my::Var2> (R"(67)");
CHECK (std::get<int> (kx) == 67);
}
{
auto kx = from_json<my::Var2> (R"(67.8)");
CHECK (std::get<float> (kx) == 67.8F);
}
{
auto kx = from_json<my::Var2> (R"("test")");
CHECK (std::get<std::string> (kx) == "test");
}
my::Var2 v = 1;
CHECK (to_json<my::Var2> (v) == "1");
} |
Beta Was this translation helpful? Give feedback.
-
Another thing, you may want to consider doing something like auto jv = daw::json::json_value( ptr, sz );
switch( jv.type( ) ) {
case daw::json::JsonBaseParseTypes::Number:
if( auto sv = jv.get_string_view( );
std::find_if_not( sv.begin( ), sv.end( ), []( char c ) {
return '0' <= c and c <= '9';
} ) == sv.end( ) ) {
// Only digits
return as<int>( jv );
}
return as<float>( jv );
case daw::json::JsonBaseParseTypes::Bool:
return as<bool>( jv );
case daw::json::JsonBaseParseTypes::String:
return std::string{ ptr, sz };
case daw::json::JsonBaseParseTypes::Array:
case daw::json::JsonBaseParseTypes::Class:
case daw::json::JsonBaseParseTypes::None:
case daw::json::JsonBaseParseTypes::Null:
default:
std::abort( );
} inside the Var2Constructor. Why throw when you can avoid it. |
Beta Was this translation helpful? Give feedback.
-
I think it is reasonable that the ostream writer is in a separate header with a disable option |
Beta Was this translation helpful? Give feedback.
-
b4fd667 should allow using cmake/compile flags to disable the ostream and/or the FILE * writers |
Beta Was this translation helpful? Give feedback.
If this is representative and there is no tag member to dispatch with, then I would look into
json_raw
and a custom constructor where you can inspect the data.struct FooConstructor {
std::variant<...> operaetor( )( char const * s, size_t sz ) const {
auto jv = daw:::json::json_value( string_view( s, sz ) );
...
}
};