I have a boost::any object, and I would like to check its type.
typedef boost::any Value;
Value a = 12;
if(a.type() == typeid(int)) {
std::cout << boost::any_cast<int>(a) << std::endl;
}
This is easy enough when the type is defined, however how would I achieve a the same result when the type is not defined (i.e. because its value has not been set yet).
Value b;
if(b is undefined) {
std::cout << "b is not defined" << std::endl;
}
boost::any::empty will return true if there is no value.
Demo
#include "boost/any.hpp"
#include <iostream>
int main()
{
boost::any a = 42;
if (!a.empty())
std::cout << "a has a value\n";
boost::any b;
if (b.empty())
std::cout << "b does not have a value\n";
}
Alternatively, you can use boost::any::type like you did in the first example and, if there's no value, it will return typeid(void):
Demo 2
boost::any a = 42;
std::cout << std::boolalpha << (a.type() == typeid(int)) << std::endl; // true
boost::any b;
std::cout << std::boolalpha << (b.type() == typeid(void)) << std::endl; // true
Related
I have multiple functions that have long and similar implementations. The only difference is they call different calls, which is basically based on the function name like below.
// A.h
class A : public ParentA
{
public:
explicit A(B& b);
~A() override = default;
// accessors
C does_same_thing1() const;
C does_same_thing2() const;
C does_same_thing3() const;
// ...
}
// A.cpp
C A::does_same_thing1() const
{
...
return xyz.values().thing1();
}
C A::does_same_thing2() const
{
...
return xyz.values().thing2();
}
C A::does_same_thing3() const
{
...
return xyz.values().thing3();
}
I wonder if there's a way to dynamically fill out the functions that are almost the same except the accessors they call (thing1(), thing2(), and thing3(), and this actually happens more than once, not just on the return line) based on their function names. Would this be possible in C++?
Thanks!
You can write one function template and let the caller choose what is to be returned:
template <typename F>
auto foo(F f) {
...
return f(xyz.values());
}
Details depend on details you left out from the question. For example, is the type of xyz.values() available to the caller? Also, it is up to you to let the caller pick f or write wrappers:
auto does_same_thing1() {
foo([](auto& x) { return x.thing1(); }
}
// ... and same for the others
Some options are:
Using an abstract and overriding the parts you require.
Using lambas and passing in the functions your require.
Using template functions is kind of a mix of the two above, but I'll let someone else explain that one.
Create your base class
class Base
{
protected:
int value;
public:
virtual void differentFunction(int mathThing) = 0;
void longFunction()
{
value = 0;
std::cout << "I do a lot of steps" << std::endl;
std::cout << "Step 1" << std::endl;
value++;
std::cout << "Step 2" << std::endl;
value++;
std::cout << "Step 3" << std::endl;
value++;
std::cout << "Step 4" << std::endl;
value++;
std::cout << "Step 5" << std::endl;
value++;
std::cout << "Step 6" << std::endl;
//And finally I do a unique thing
differentFunction(3);
std::cout << "Resulting value: " << value << std::endl;
}
void longLamdaFunction(std::function<void(int& value, int mathThing)> mathFunction)
{
value = 0;
std::cout << "I do a lot of steps" << std::endl;
std::cout << "Step 1" << std::endl;
value++;
std::cout << "Step 2" << std::endl;
value++;
std::cout << "Step 3" << std::endl;
value++;
std::cout << "Step 4" << std::endl;
value++;
std::cout << "Step 5" << std::endl;
value++;
std::cout << "Step 6" << std::endl;
//And finally I do a unique thing
mathFunction(value, 3);
std::cout << "Resulting value: " << value << std::endl;
}
};
Create an overriding class
class Derived1 : public Base
{
public:
void differentFunction(int mathThing) override
{
std::cout << "I multiply the value" << std::endl;
value *= mathThing;
}
};
Create a different overriding class
class Derived2 : public Base
{
public:
void differentFunction(int mathThing) override
{
std::cout << "I divide the value" << std::endl;
value /= mathThing;
}
};
Example on use, you can see the Lambda example here too
int main()
{
Derived1 d1;
Derived2 d2;
std::cout << "\nUsing multiple interface\n";
d1.longFunction();
std::cout << "\nUsing divide interface\n";
d2.longFunction();
std::cout << "\nUsing add lamda\n";
//I now add them
auto addFunction = [](int& x, int y) -> void { x += y; };
d1.longLamdaFunction(addFunction);
std::cout << "\nUsing subtract lamda\n";
//I now subtract them
auto subtractFunction = [](int& x, int y) -> void { x -= y; };
d1.longLamdaFunction(subtractFunction);
}
I'm unable to have this code running properly on Ubuntu 20.04 (gcc), and I'm only able to have the template deducted for the else branch (integers), ignoring all the deductions for bool, double and std:string
I even tried the std::enable_if but to no avail...
What am I'm missing here?
#include <iostream>
#include <string>
#include <cstdint>
namespace myns
{
using UInt64 = uint64_t;
using Int64 = int64_t;
using UInt32 = uint32_t;
using Int32 = int32_t;
using UInt16 = uint16_t;
using Int16 = int16_t;
using UInt8 = uint8_t;
using Int8 = int8_t;
}
bool function_int (myns::UInt64& i)
{
i = 10;
}
bool function_float (double& d)
{
d = 4.3;
}
bool function_bool (bool& b)
{
b = true;
}
bool function_str(std::string& s)
{
s = "Hello World";
}
template <typename T>
bool function(T&& value)
{
if constexpr (std::is_same_v<T, bool>)
{
std::cout << "Returning bool" << std::endl;
return function_bool (std::forward<T> (value));
}
else if constexpr (std::is_same_v<T, double>)
{
std::cout << "Returning double" << std::endl;
return function_float (std::forward<T> (value));
}
else if constexpr (std::is_same_v<T, std::string>)
{
std::cout << "Returning string" << std::endl;
return function_str (std::forward<T> (value));
}
else
{
std::cout << "Returning integer" << std::endl;
myns::UInt64 val;
auto ret = function_int (val);
value = val;
}
}
using namespace myns;
int main()
{
UInt64 ui64;
Int64 i64;
UInt32 ui32;
Int32 i32;
UInt16 ui16;
Int16 i16;
UInt8 ui8;
Int8 i8;
std::string str;
bool boolean;
double dbl;
function(str);
function(ui64);
function(i64);
function(ui32);
function(i32);
function(ui16);
function(i16);
function(ui8);
function(i8);
function(boolean);
function(dbl);
std::cout << "Uint64: " << ui64 << std::endl;
std::cout << "Int64: " << i64 << std::endl;
std::cout << "UInt32: " << ui32 << std::endl;
std::cout << "Int32: " << i32 << std::endl;
std::cout << "UInt16: " << ui16 << std::endl;
std::cout << "Int16: " << i16 << std::endl;
std::cout << "UInt8: " << ui8 << std::endl;
std::cout << "Int8: " << i8 << std::endl;
std::cout << "String: " << str << std::endl;
std::cout << "bool: " << boolean << std::endl;
std::cout << "double: " << dbl << std::endl;
}
Output:
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Uint64: 10
Int64: 10
UInt32: 10
Int32: 10
UInt16: 10
Int16: 10
UInt8:
Int8:
String:
bool: 1
double: 10
I've been banging my head for almost a day with no solutions on site, I even though of giving up and creating a template specialization for all the types, but I this is a lot of code "repetition" that could be all done in a small template
Thanks in advance!
T is being deduced as a reference here. For example, when invoked with a double, the argument is double & && (which collapses to double &). T is double &, which is not the same thing as double. std::is_same_v<double &, double> is indeed false.
One solution would be to remove any reference from T before checking:
std::is_same_v<std::remove_reference_t<T>, double>
Side note: you have several functions returning bool but without any return statement. This causes undefined behavior.
Thanks to #cdhowie the proper code should be like the one below
#include <iostream>
#include <string>
#include <cstdint>
namespace myns
{
using UInt64 = uint64_t;
using Int64 = int64_t;
using UInt32 = uint32_t;
using Int32 = int32_t;
using UInt16 = uint16_t;
using Int16 = int16_t;
using UInt8 = uint8_t;
using Int8 = int8_t;
}
bool function_int (myns::UInt64& i)
{
i = 10;
}
bool function_float (double& d)
{
d = 4.3;
}
bool function_bool (bool& b)
{
b = true;
}
bool function_str(std::string& s)
{
s = "Hello World";
}
template <typename T>
bool function(T&& value)
{
if constexpr (std::is_same_v<std::remove_reference_t<T>, bool>)
{
std::cout << "Returning bool" << std::endl;
return function_bool (std::forward<T> (value));
}
else if constexpr (std::is_same_v<std::remove_reference_t<T>, double>)
{
std::cout << "Returning double" << std::endl;
return function_float (std::forward<T> (value));
}
else if constexpr (std::is_same_v<std::remove_reference_t<T>, std::string>)
{
std::cout << "Returning string" << std::endl;
return function_str (std::forward<T> (value));
}
else
{
std::cout << "Returning integer" << std::endl;
myns::UInt64 val;
auto ret = function_int (val);
value = val;
return value;
}
}
using namespace myns;
int main()
{
UInt64 ui64;
Int64 i64;
UInt32 ui32;
Int32 i32;
UInt16 ui16;
Int16 i16;
UInt8 ui8;
Int8 i8;
std::string str;
bool boolean;
double dbl;
// Ignore the return values, this is just for prototyping..
function(str);
function(ui64);
function(i64);
function(ui32);
function(i32);
function(ui16);
function(i16);
function(ui8);
function(i8);
function(boolean);
function(dbl);
std::cout << "Uint64: " << ui64 << std::endl;
std::cout << "Int64: " << i64 << std::endl;
std::cout << "UInt32: " << ui32 << std::endl;
std::cout << "Int32: " << i32 << std::endl;
std::cout << "UInt16: " << ui16 << std::endl;
std::cout << "Int16: " << i16 << std::endl;
std::cout << "UInt8: " << ui8 << std::endl;
std::cout << "Int8: " << i8 << std::endl;
std::cout << "String: " << str << std::endl;
std::cout << "bool: " << boolean << std::endl;
std::cout << "double: " << dbl << std::endl;
}
The code that works is the following:
#include <boost/variant.hpp>
#include <string>
#include <map>
#include <iostream>
int main(int argc, char** argv) {
std::map<std::string, boost::variant<int, std::string> > values;
values["a"] = 10;
values["b"] = "bstring";
values["c"] = "cstring";
for (const auto &p : values) {
std::cout << p.first << " = ";
if (p.second.type() == typeid(std::string)) {
std::cout << boost::get<std::string>( p.second ) << " (found string)" << std::endl;
} else if ( p.second.type() == typeid(int)) {
std::cout << boost::get<int>( p.second ) << " (found int)" << std::endl;
} else if ( p.second.type() == typeid(bool)) {
std::cout << boost::get<bool>( p.second ) << " (found bool)" << std::endl;
} else {
std::cout << " not supported type " << std::endl;
}
}
}
The output (g++ test.cpp -std=c++11):
a = 10
b = bstring
c = cstring
The code that does not work is exactly the same, except the line that defines the std::map
modifying the line of the map definition to:
std::map<std::string, boost::variant<int, std::string, bool> > values;
the output is different:
a = 10
b = c =
The if statement that refers to std::string comparison does not succeed. What is the problem?
In your code, values["b"] = "bstring"; creates a bool value, when both std::string and bool are in the variant type.
A fix is values["b"] = std::string("bstring");.
Or, in C++14:
using namespace std::string_literals;
values["b"] = "bstring"s;
It is a well-known annoyance that string literals better convert to bool than to std::string:
#include <iostream>
#include <string>
void f(std::string) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
void f(std::string const&) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
void f(bool) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
int main() {
f("hello");
}
Outputs:
void f(bool)
Suppose I have a variable, double x, as a result of some calculations, which can have any value, including zero, and I need it passed to std::cout. How can I avoid printing x if its value is zero?
As an example, this will print 1+<value_of_x> if x, else just 1:
std::cout << (x ? "1+" : "1") << x << '\n';
Is there a way to make the same but for x? Something like the following nonsense:
std::cout << (x ? ("1+" << x) : "1") << '\n';
I should probably add that I am not advanced in C++.
You could say
std::cout << (x ? "1+" + std::to_string(x) : "1") << '\n';
but
if (x)
std::cout << "1+" << x << '\n';
else
std::cout << "1" << '\n';
is perhaps more readable.
(I consider this largely a matter of personal preference.)
If x is 0, don't print it:
if (x != 0)
std::cout << x << '\n';
Any further variations should be self-evident.
Using an if statement would be a simple and readable approach:
if (x)
std::cout << "1+" << x;
else
std::cout << "1";
std::cout << '\n';
Or even:
std::cout << "1";
if (x) std::cout << "+" << x;
std::cout << '\n';
But, if you really want to print out the value inline, you can define a custom operator<< to format the value however you want:
struct to_coefficient_str
{
double m_value;
to_coefficient_str(double value) : m_value(value) {}
void print(std::ostream &out) const
{
out << "1";
if (m_value)
out << "+" << m_value;
}
};
std::ostream& operator<<(std::ostream &out, const to_coefficient_str &ce)
{
ce.print(out);
return out;
}
Then you can use it like this:
std::cout << to_coefficient_str(x) << '\n';
This question already has answers here:
Pattern to avoid nested try catch blocks?
(16 answers)
Closed 6 years ago.
I have a yaml-cpp which always converts into a std::string, and sometimes also into something else. For example, if the string actually is "3.14", it would also convert into double. I'd first like to try int, then double, then bool, and if that doesn't work, convert to a std::string. Alright, so let's nest those try-catches:
try {
const int a = node.as<int>();
std::cout << "int!" << a << std::endl;
} catch (YAML::BadConversion) {
try {
const double a = node.as<double>();
std::cout << "double!" << a << std::endl;
} catch (YAML::BadConversion) {
try {
const bool a = node.as<bool>();
std::cout << "bool!" << a << std::endl;
} catch (YAML::BadConversion) {
const std::string a = node.as<std::string>();
std::cout << "string!" << a << std::endl;
}
}
}
Hm, the deeper and deeper nesting tells me that this isn't the best way to write that code.
Any suggestions on how to improve the design here? Flat nesting would certainly be advised.
You may put it in a function like:
template<typename N, typename T>
bool tryParseNode(N& node, T& val) {
try {
val = node.as<T>();
return true;
} catch (YAML::BadConversion) {
return false;
}
}
then:
int a;
double d;
bool b;
std::string s;
if (tryParseNode(node, a) {
std::cout << "int!" << a << std::endl;
}
else if (tryParseNode(node, d) {
std::cout << "double!" << d << std::endl;
}
else if (tryParseNode(node, b) {
std::cout << "bool!" << b << std::endl;
}
else if (tryParseNode(node, s) {
std::cout << "string!" << s << std::endl;
}
Try the other way round:
Convert into to a string, then try bool, etc.
Everything within a single try-catch and ignore the exception.
Using exceptions for normal control flow is considered bad practice. In this case, the as method uses the `YAML::convert::decode' method to attempt to convert the node into the requested type returning a false if it fails instead of throwing an exception.
int anInt;
double aDouble;
bool aBool;
if (YAML::convert <int>::decode (node, anInt))
std::cout << "int!" << anInt << std::endl;
else
if (YAML::convert <double>::decode (node, aDouble))
std::cout << "double!" << aDouble << std::endl;
else
if (YAML::convert <bool>::decode (node, aBool))
std::cout << "double!" << aBool << std::endl;
else
std::cout << "string!" << node.as <std::string> () << std::endl;
which could be further simplified to
template <typename value_type>
std::optional <value_type> decode (YAML::Node const & Node)
{
value_type Value;
if (YAML::convert <value_type>::decode (node, Value))
return { Value };
else
return {};
}
if (auto anInt = decode <int> (node))
std::cout << "int!" << *anInt << std::endl;
else
if (auto aDouble = decode <double> (node))
std::cout << "double!" << *aDouble << std::endl;
else
if (auto aBool = decode <bool> (node))
std::cout << "double!" << *aBool << std::endl;
else
std::cout << "string!" << node.as <std::string> () << std::endl;