I made some template functions to ease the process of extracting data from json using rapidjson . I'm using visual studio 2017 so I have access to c++ 17 features and also I installed clang 8.0.1 and added it to visual studio because clang errors and warnings are better than msvc .
now this is the problem :
template <std::size_t N>
using JsonMembers = std::array<const char*, N>;
template <class T, std::size_t N>
using JsonVars = std::array<T *, N>;
namespace JsonUtils
{
template <std::size_t N>
bool VerifyMembers(const rapidjson::Value& JsonValue, const std::array<const char*, N> &members)
{
for (auto member : members)
if (!JsonValue.HasMember(member))
return false;
return true;
}
template <class T, bool Optional, std::size_t N>
bool DumpVarsOrOpts(const rapidjson::Value& JsonValue, const JsonMembers<N> &members, const JsonVars<T, N> &vars)
{
if constexpr (!Optional)
{
if (!VerifyMembers(JsonValue, members))
return false;
}
auto members_begin = std::begin(members);
auto members_end = std::end(members);
auto vars_begin = std::begin(vars);
auto vars_end = std::end(vars);
for (; members_begin != members_end && vars_begin != vars_end; ++members_begin, ++vars_begin)
{
if (!JsonValue.HasMember(*members_begin))
{
continue;
}
if constexpr (std::is_same_v<T, bool>)
{
**vars_begin = JsonValue[*members_begin].GetBool();
}
else if constexpr (std::is_integral_v<T>)
{
if constexpr (std::is_unsigned_v<T>)
{
if constexpr (sizeof(T) != sizeof(int64_t))
**vars_begin = JsonValue[*members_begin].GetUint();
else
**vars_begin = JsonValue[*members_begin].GetUint64();
}
else
{
if constexpr (sizeof(T) != sizeof(int64_t))
**vars_begin = JsonValue[*members_begin].GetInt();
else
**vars_begin = JsonValue[*members_begin].GetInt64();
}
}
else if constexpr (std::is_floating_point_v<T>)
{
**vars_begin = JsonValue[*members_begin].GetDouble();
}
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, rad::string> ||
std::is_same_v<T, std::optional<std::string>> || std::is_same_v<T, std::optional<rad::string>>)
{
**vars_begin = JsonValue[*members_begin].GetString();
}
else // here the problem
{
static_assert(false, "unsupported type !"); // this is hit by clang but not msvc
}
}
return true;
}
template <class T, std::size_t N>
bool DumpVars(const rapidjson::Value& JsonValue, const JsonMembers<N> &members, const JsonVars<T, N> &vars)
{
return DumpVarsOrOpts(JsonValue, members, vars); }
template <class T, std::size_t N>
void DumpOpts(const rapidjson::Value& JsonValue, const JsonMembers<N> &members, const JsonVars<T, N> &vars)
{
DumpVarsOrOpts<T, true, N>(JsonValue, members, vars);
}
}
the class rad::string is derived from std::string and doesn't have any additional members . I made it to add some operations to std::string such as split, replace_all, easy conversion from utf-8 to utf-16 and vice versa . so it basically looks like this :
namespace rad
{
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
>
class basic_string : public std::basic_string<CharT, Traits, Allocator>
{
... some methods
}
using string = basic_string<char>;
using wstring = basic_string<wchar_t>;
using u8string = string;
using u16string = basic_string<char16_t>;
using u32string = basic_string<char32_t>;
}
now I used the functions like this :
bool some_class::some_method(const rapidjson::Value & Jv)
{
if (!JsonUtils::DumpVars<std::string>(Jv, JsonMembers<4>{ "m1", "m2", "m3", "m4" },
{ &v1, &v2, &v3, &v4})) // the are all std::string
return false;
JsonUtils::DumpOpts<std::optional<std::string>>(Jv, JsonMembers<2>{ "mopt1", "mopt2" }, { &varopt1, &varopt2 }); // the are all std::optional<std::string>
return true;
}
this compiles fine with msvc with c++ 17 enabled although the ide shows some errors around the last else branch
when I tried to compile it using clang I got an error :
error : static_assert failed "unsupported type !"
note: in instantiation of function template specialization 'JsonUtils::DumpVars<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, 4>' requested here
it seems that clang doesn't handle this if constexpr well . I thought I needed to enable c++ 17 features for clang but I remembered that the rest of the code contains many c++ 17 code and if it lacked c++ 17 support it would have complained about the if constexpr expression at the first place .
can any one here help me find the problem !
Aucun commentaire:
Enregistrer un commentaire