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;
}
Related
I would like to implement a table that will consist of some names of data types so that I will be able use them in loop to cout my function. How to do it? I have already tried with the table that is in my code but it doesn't work. Probably it's something with pointers.
#include <iostream>
#include <limits>
#include <iomanip>
using namespace std;
template<typename T>
void sizeF(string opis) {
int x = sizeof(T);
if (x==1)
cout << "Rozmiar typu "+opis+" to " << x << " bajt.\n";
else if (x==2 || x==4)
cout << "Rozmiar typu "+opis+" to " << x << " bajty.\n";
else
cout << "Rozmiar typu "+opis+" to " << x << " bajtów.\n";
}
template<typename T>
void maxMinF(string opis)
{
cout << opis << ": minimalna wartosc: " << numeric_limits<T>::min() << ", maksymalna wartosc: " << numeric_limits<T>::max() << endl;
}
int main()
{
char tab[1][15] = {"short int"};
sizeF<tab[0]>(tab[0]);
sizeF<int>("int");
sizeF<unsigned long long>("unsigned long long");
sizeF<bool>("bool");
sizeF<char>("char");
sizeF<double>("double");
sizeF<long double>("long double");
sizeF<long long>("long long");
sizeF<short>("short");
sizeF<unsigned short>("usigned short");
cout << endl;
maxMinF<short int>("short int");
maxMinF<int>("int");
maxMinF<unsigned long long>("unsigned long long");
maxMinF<bool>("bool");
maxMinF<char>("char");
maxMinF<double>("double");
maxMinF<long double>("long double");
maxMinF<long long>("long long");
maxMinF<short>("short");
maxMinF<unsigned short>("usigned short");
return 0;
}
I think you are taking a terrible route in doing what you're doing.
You should probably refer to Boost.TypeIndex library instead. Look at this:
#include <iostream>
#include <boost/type_index.hpp>
class Widget {
};
int main() {
Widget w1;
Widget& w2 = w1;
Widget const w3;
Widget const& w4 = w1;
std::cout << boost::typeindex::type_id_with_cvr<decltype(w1)>() << '\n';
std::cout << boost::typeindex::type_id_with_cvr<decltype(w2)>() << '\n';
std::cout << boost::typeindex::type_id_with_cvr<decltype(w3)>() << '\n';
std::cout << boost::typeindex::type_id_with_cvr<decltype(w4)>() << '\n';
}
which outputs exactly what you'd expect:
Widget
Widget&
Widget const
Widget const&
Here's the demo.
I want to convert a four-byte string to either int32 or uint32 in c++.
This answer helped me to write the following code:
#include <string>
#include <iostream>
#include <stdint.h>
int main()
{
std::string a("\xaa\x00\x00\xaa", 4);
int u = *(int *) a.c_str();
int v = *(unsigned int *) a.c_str();
int x = *(int32_t *) a.c_str();
int y = *(uint32_t *) a.c_str();
std::cout << a << std::endl;
std::cout << "int: " << u << std::endl;
std::cout << "uint: " << v << std::endl;
std::cout << "int32_t: " << x << std::endl;
std::cout << "uint32_t: " << y << std::endl;
return 0;
}
However the outputs are all the same, where the int (or int32_t) values are correct, but the unsigned ones are wrong. Why does not the unsigned conversions work?
// output
int: -1442840406
uint: -1442840406
int32_t: -1442840406
uint32_t: -1442840406
Pythons struct.unpack, gives the right conversion
In [1]: import struct
In [2]: struct.unpack("<i", b"\xaa\x00\x00\xaa")
Out[2]: (-1442840406,)
In [3]: struct.unpack("<I", b"\xaa\x00\x00\xaa")
Out[3]: (2852126890,)
I would also like a similar solution to work for int16 and uint16, but first things first, since I guess an extension would be trivial if I manage to solve this problem.
You need to store the unsigned values in an unsigned variables and it will work:
#include <string>
#include <iostream>
#include <stdint.h>
int main()
{
std::string a("\xaa\x00\x00\xaa", 4);
int u = *(int *) a.c_str();
unsigned int v = *(unsigned int *) a.c_str();
int32_t x = *(int32_t *) a.c_str();
uint32_t y = *(uint32_t *) a.c_str();
std::cout << a << std::endl;
std::cout << "int: " << u << std::endl;
std::cout << "uint: " << v << std::endl;
std::cout << "int32_t: " << x << std::endl;
std::cout << "uint32_t: " << y << std::endl;
return 0;
}
When you cast the value to unsigned and then store it in a signed variable, the compiler plays along. Later, when you print the signed variable, the compiler generates code to print a signed variable output.
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;
I am trying to convert a uint64_t to a uint8_t. I know this makes no sense normaly but since the JSON Library converts all numeric values to a uint64_t or int64_t I have to convert it back. I am always sure I do not receive values which will not fit into the uint8_t.
Now when I compile and run the following code on OSx everything works as expected. But as soon as I move to a Raspberry Pi 2 the code no longer works. The value is 0.
Can anybody explain why this is happening? And does somebody has a better solution?
#include <iostream>
#include "json.h"
using JSON = nlohmann::json;
typedef struct {
uint8_t boardId;
uint8_t commandGroupId;
uint8_t commandId;
} ExternalMessageType;
int main(int argc, const char * argv[])
{
JSON x;
ExternalMessageType y;
x["board-id"] = 1;
x["command-group-id"] = 1;
x["command-id"] = 11;
y.boardId = static_cast<uint8_t>(x["board-id"]);
y.commandGroupId = static_cast<uint8_t>(x["command-group-id"]);
y.commandId = static_cast<uint8_t>(x["command-id"]);
std::cout << "Board: " << (int)y.boardId << std::endl;
std::cout << "Group: " << (int)y.commandGroupId << std::endl;
std::cout << "Command: " << (int)y.commandId << std::endl;
if (y.commandGroupId == 1) {
std::cout << "Command Group is ok." << std::endl;
switch (y.commandId) {
case 11: {
std::cout << "Speed Message" << std::endl;
} break;
}
} else {
std::cout << "Command Group is not ok." << std::endl;
}
return 0;
}
I've a class withmap<string,vector<string>>.
I want to give a user a member function to receive the value for a key in different formats than std::vector(string):
vector(string),
string,
vector(int),
vector(float) and
bool
example:
bool x = (bool) myClass["dummy_boolean_type"]
x = myClass["dummy_boolean_type"].as<bool>
int y = (int) myClass["dummy_boolean_type"]
Can someone have an example what is the best way to achieve it ?
(without a use in Boost)
You cannot provide your class with any member function or functions
that will support the two constructions you want:
T x = myClassInstance["key"].as<T> // (1)
T x = (T) myClassInstance["key"] // (2)
In the case of (1), the immediate reason is simply that the construction is
not legal C++. So let's suppose it is replaced by:
T x = myClassInstance["key"].as<T>() // (1a)
But this doesn't help, and the reason is the same for both (1a) and (2):
The expression myClassInstance["key"] will have to evaluate to some object e or reference to such that is returned by:
myClass::operator[](std::string const &);
This e is the vector<string> to which key maps in your
map<string,vector<string> data member of myClass. It is not myClassInstance.
So what you are asking for are member functions of myClass that will support
the constructions:
T x = e.as<T> // (1b)
T x = (T) e // (2b)
where e is an std::vector<std::string>.
Clearly, nothing you can do in myClass can address your requirement. In
(1b) and (2b), myClass is nowhere to be seen.
Is there any template member function of std::vector<std::string>:
template<typename T>
T as() const;
that has the behaviour you want for (1b)?
Does std::vector<std::string> have any template member function:
template<typename T>
operator T() const;
that has the behaviour you want for (2b)?
No and No.
However...
You can implement an as template member function of myClass that
supports conversions such as you mention. Its signature - of course -
would be:
template<typename T>
T myClass::as(std::string const & key) const;
and you would invoke it like:
T x = myClassInstance.as<T>("key") // (1c)
I'll sketch an implemention that assumes we're content with the
conversions from std::vector<std::string> to:
std::string
std::vector<int>
bool
which will be enough to get you under way.
To convert an std::vector<std::string> vs to std::string I'll concatenate
the elements of vs.
To convert an std::vector<std::string> vs to std::vector<int> I'll convert each element of vs from a decimal numeral, if I can, to the
integer the numeral represents, and return a vector of those integers. Without
prejudice to other policies I'll throw an std::invalid_argument exception
when an element doesn't trim to a decimal numeral.
I am spoilt for choice as to what you might mean by converting an std::vector<std::string>
to bool, so I will arbitrarily say that vs is true if I can convert it
to a vector<int> of which any element is non-0 and is false if I can convert
it to a vector<int> in which all elements are 0.
The sketch:
#include <type_traits>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
namespace detail {
template<typename T>
struct convert_to
{
static T from(std::vector<std::string> const & vs) {
static constexpr bool always_false = !std::is_same<T,T>::value;
static_assert(always_false,
"Calling `convert_to<T>::from` for unimplemented `T`");
return *(T*)nullptr;
}
};
template<>
std::string convert_to<std::string>::from(std::vector<std::string> const & vs)
{
std::string s;
for ( auto const & e : vs ) {
s += e;
}
return s;
}
template<>
std::vector<int>
convert_to<std::vector<int>>::from(std::vector<std::string> const & vs)
{
auto lamb = [](std::string const & s) {
std::size_t lastoff = s.find_last_not_of(" \t\f\v\n\r");
int i;
try {
std::size_t nlen;
i = std::stoi(s,&nlen);
if (nlen <= lastoff) {
throw std::invalid_argument("");
}
}
catch(std::invalid_argument const & e) {
throw std::invalid_argument(
"Cannot convert \"" + s + "\" to int");
}
return i;
};
std::vector<int> vi;
std::transform(vs.begin(),vs.end(),std::back_inserter(vi),lamb);
return vi;
}
template<>
bool convert_to<bool>::from(std::vector<std::string> const & vs)
{
auto vi = convert_to<std::vector<int>>::from(vs);
for (auto const & i : vi) {
if (i) {
return true;
}
}
return false;
}
} // namespace detail
struct myClass // Your class
{
// Whatever...
std::vector<std::string> & operator[](std::string const & key) {
return _map[key];
}
template<typename T>
T as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
// Whatever...
private:
std::map<std::string,std::vector<std::string>> _map;
};
The one take-away point here is the use of template<typename T>
detail::struct convert_to, with its solitary static member function:
T from(std::vector<std::string> const & vs)
which in the default instantiation will provoke a static_assert failure
reporting that no conversion to T from std::vector<std::string> has been
defined.
Then, for each type U to which you want a conversion, you have just to
write a specializing definition:
template<>
U convert_to<U>::from(std::vector<std::string> const & vs);
as you see fit, and the construction (1c) will use it as per:
template<typename T>
T myClass::as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
Here's an illustrative progam you can append to the sketch:
#include <iostream>
using namespace std;
template<typename T>
static void print_vec(std::vector<T> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << e << " ";
}
cout << "}\n";
}
static void print_vec(std::vector<std::string> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << '\"' << e << "\" ";
}
cout << "}\n";
}
int main()
{
myClass f;
f["int_vec"] = vector<string>{"0","1 "," 2"};
cout << "f[\"int_vec\"] = "; print_vec(f["int_vec"]);
f["true_vec"] = vector<string>{"0"," 1 ","0"};
cout << "f[\"true_vec\"] = "; print_vec(f["true_vec"]);
f["false_vec"] = vector<string>{"0"," 0","0 "};
cout << "f[\"false_vec\"] = "; print_vec(f["false_vec"]);
f["not_int_vec0"] = vector<string>{"0","1","2",""};
cout << "f[\"not_int_vec0\"] = "; print_vec(f["not_int_vec0"]);
f["not_int_vec1"] = vector<string>{"0","#","2",};
cout << "f[\"not_int_vec1\"] = "; print_vec(f["not_int_vec1"]);
f["not_int_vec2"] = vector<string>{"0"," 1$","2",};
cout << "f[\"not_int_vec2\"] = "; print_vec(f["not_int_vec2"]);
cout << "f.as<string>(\"int_vec\") = \""
<< f.as<string>("int_vec") << '\"' << endl;
cout << "f.as<string>(\"true_vec\") = \""
<< f.as<string>("true_vec") << '\"' << endl;
cout << "f.as<string>(\"false_vec\") = \""
<< f.as<string>("false_vec") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec0\") = \""
<< f.as<string>("not_int_vec0") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec1\") = \""
<< f.as<string>("not_int_vec1") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec2\") = \""
<< f.as<string>("not_int_vec2") << '\"' << endl;
vector<int> va = f.as<vector<int>>("int_vec");
cout << "f.as<vector<int>>(\"int_vec\") = ";
print_vec(f.as<vector<int>>("int_vec"));
cout << boolalpha << "f.as<bool>(\"true_vec\") = "
<< f.as<bool>("true_vec") << endl;
cout << boolalpha << "f.as<bool>(\"false_vec\") = "
<< f.as<bool>("false_vec") << endl;
try {
cout << "f.as<vector<int>>(\"not_int_vec0\")...";
auto b = f.as<vector<int>>("not_int_vec0");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec1\")...";
auto b = f.as<vector<int>>("not_int_vec1");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec2\")...";
auto b = f.as<vector<int>>("not_int_vec2");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
// char ch = f.as<char>("int_vec"); <- static_assert fails
return 0;
}
It outputs:
f["int_vec"] = { "0" "1 " " 2" }
f["true_vec"] = { "0" " 1 " "0" }
f["false_vec"] = { "0" " 0" "0 " }
f["not_int_vec0"] = { "0" "1" "2" "" }
f["not_int_vec1"] = { "0" "#" "2" }
f["not_int_vec2"] = { "0" " 1$" "2" }
f.as<string>("int_vec") = "01 2"
f.as<string>("true_vec") = "0 1 0"
f.as<string>("false_vec") = "0 00 "
f.as<string>("not_int_vec0") = "012"
f.as<string>("not_int_vec1") = "0#2"
f.as<string>("not_int_vec2") = "0 1$2"
f.as<vector<int>>("int_vec") = { 0 1 2 }
f.as<bool>("true_vec") = true
f.as<bool>("false_vec") = false
f.as<vector<int>>("not_int_vec0")...Cannot convert "" to int
f.as<vector<int>>("not_int_vec1")...Cannot convert "#" to int
f.as<vector<int>>("not_int_vec2")...Cannot convert " 1$" to int
(gcc 5.1, clang 3.6, C++11)