I come to you today with another question that my brain can't process by itself: I got a cpp file that includes optional as a header file. Unfortunately, this works only on c 17 forwards, and I'm trying to compile it in c 14. This cpp file uses optional like this
std::optional<std::string> GetStringPropertyValueFromJson(const std::string& Property, const web::json::value& Json)
{
if (Json.has_field(utility::conversions::to_string_t(Property)))
{
auto& propertyValue = Json.at(utility::conversions::to_string_t(Property));
if (propertyValue.is_string())
{
return std::optional<std::string>{utility::conversions::to_utf8string(propertyValue.as_string())};
}
}
return std::nullopt;
}
and then the function is used to assign values like this:
std::string tokenType = GetStringPropertyValueFromJson("token_type", responseContent).value_or("");
std::string accessToken = GetStringPropertyValueFromJson("access_token", responseContent).value_or("");
Please help me with a proper substitution for OPTIONAL. Thanks and much love
PS: From what i've read, you can replace optional with pair somehow in order to get a similar result, but I don't really know how exactly.
PPS: I am new here so any tips on how to better write my questions or anything else are greatly appreciated :)
CodePudding user response:
I guess in C 14 the optional
header could be included by #include <experimental/optional>
.
CodePudding user response:
Change your method signature to
std::string GetStringPropertyValueFromJson(const std::string& Property, const web::json::value& Json)
and in the end just return the empty string
return "";
Then later in your code use it without std::optional::value_or
:
std::string tokenType = GetStringPropertyValueFromJson("token_type", responseContent);
The logic is exactly the same and you don't use std::optional
.
I see now your other question about possibility to use std::pair
. Yes, you could also change your method to:
std::pair<std::string, bool> GetStringPropertyValueFromJson(const std::string& Property, const web::json::value& Json)
and return std::make_pair(valueFromJson, true)
in case your json property has been found, or std::make_pair("", false)
in case it was not. This also solves the problem with empty (but existing) json property.
CodePudding user response:
A poor mans optional string that should be sufficient for your code is this:
struct my_nullopt {};
struct my_optional {
private:
std::string value;
bool has_value = false;
public:
my_optional(my_nullopt) {}
my_optional(const std::string& v) : value(v),has_value(true) {}
T value_or(const std::string& v) {
return has_value ? value : v;
}
};
Its a rather limited interface, for example it is not possible to set the value after construction. But it appears that you do not need that.
Alternatively you can use boost/optional
.
Note that the tip you got about using a pair
is just what I did above: The value and a bool
. Just that std::pair
is for cases where you cannot give better names than first
and second
(eg in generic code), but it is simple to provide a better interface than std::pair
does here. With a pair the value_or
would be something along the line of x.first ? x.second : ""
.
PS: Only in the end I realized that the code you present does not actually make use of what std::optional
has to offer. As you are calling value_or("")
, you cannot distinguish between a field with value ""
or ""
because the optional had no value. Because of that, the most simple solution is to use a plain std::string
and return ""
instead of std::nullopt
.