Serializing variadic template tuple in C++ [duplicate] - c++

I need to write a function to convert tuple to byte array.
The type of tuple may include int, long, double, std::string, char*,etc.
The size and type of tuple are arbitrary, such as
std:tuple<string, int, double> t1("abc", 1, 1.3);
or
std:tuple<char*, int, int, float, double, string> t2("abc", 1, 2, 1.3, 1.4, "hello");
I want use these tuple as input, and the byte array as return value. What should I do ?

There is also the brilliant C++ API for message pack which supports tuples natively
#include <string>
#include <sstream>
#include <tuple>
#include <msgpack.hpp>
int main() {
auto t = std::make_tuple("1", 1, 1.0);
auto buffer = std::stringstream{};
// easy peezy
msgpack::pack(buffer, t);
auto tuple_as_string = buffer.str();
}

You can use Boost Serialization for this task together with a small extension for std::tuple. However, it doesn't turn it into a byte array by default, but into something else. There is also binary_oarchive. Perhaps this fits your needs.
#include <fstream>
#include <tuple>
#include <boost/archive/text_oarchive.hpp>
#include "serialize_tuple.h" // https://github.com/Sydius/serialize-tuple
int main()
{
auto t = std::make_tuple(42,3.14,'a');
std::ofstream ofs("test.dat");
boost::archive::text_oarchive oa(ofs);
oa << t;
}

Related

Unknown type name error when inserting into unordered_map

I have a single file called main.cpp where I am trying to declare an unordered_map as shown below.
std::unordered_map<std::string, std::set<int>> firstSets;
I then try to insert a new (key, value) pair into the map as follows.
std::string decl = "decl";
std::set<int> declFirstSet = {VOID_TOK, INT_TOK, FLOAT_TOK, BOOL_TOK};
firstSets[decl] = declFirstSet;
When I do this I get the following compiler error.
C++ requires a type specifier for all declarations
firstSets[decl] = declFirstSet;
size of array has non-integer type 'std::string' (aka 'basic_string')
firstSets[decl] = declFirstSet;
So it seems to think I am declaring 'firstSets' when I am actually tring to insert into it. And it seems to treat 'firstSets' as an array instead of an unordered_map. How do I fix this?
Your std::make_pair is wrong. To get closer you need a std::set<int> instead of the std::set.
But what you really want is to just let to compiler make it for you:
firstSets.insert(std::make_pair(decl, declFirstSet));
or use an easier syntax:
firstSets[decl] = declFirstSet;
EDIT AFTER UNDERSTANDING THE PROBLEM
On the otherhand, you want firstSets to come with initial content you can reorder the declarations:
#include <set>
#include <string>
#include <unordered_map>
std::string decl{"decl"};
std::set<int> declFirstSet{1, 2, 3, 4};
std::unordered_map<std::string, std::set<int>> firstSets{{decl, declFirstSet}};
int main() {}
I don't know why it is not working, but you don't need to call make_pair...
Changing the insertion line to:
firstSets.insert({decl, declFirstSet});
Should solve your problem.
Here would be a full code example:
#include <set>
#include<string>
#include <unordered_map>
using namespace std;
int main()
{
std::unordered_map<std::string, std::set<int>> firstSets;
set<int> s = { 1, 2, 3 };
firstSets.insert({ "key", s });
}
But seems like you want them declared in global scope, so you would initialize like the following code:
#include <set>
#include<string>
#include <unordered_map>
using namespace std;
set<int> s1 = { 1, 2, 3 }, s2 = { 4, 5, 6 };
std::unordered_map<std::string, std::set<int>> firstSets{ {"key1", s1}, {"key2", s2}};
int main()
{
}

Filling a vector of bytes with random bytes

I wanted to fill a std::vector<BYTE> with random or pseudo-random bytes of data. I have written (in other word, find it) the following source code in the stackoverflow but it doesn't compile in my Visual Studio.
#include <Windows.h>
#include <vector>
#include <random>
#include <climits>
#include <algorithm>
#include <functional>
using random_bytes_engine = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, BYTE>;
int main()
{
random_bytes_engine rbe;
std::vector<BYTE> data(1000);
std::generate(data.begin(), data.end(), std::ref(rbe));
}
When I try to compile the above code Visual studio give me the following errors:
Error C2338 note: char, signed char, unsigned char, char8_t, int8_t,
and uint8_t are not allowed Messaging
Error C2338 invalid template argument for independent_bits_engine:
N4659 29.6.1.1 [rand.req.genl]/1f requires one of unsigned short,
unsigned int, unsigned long, or unsigned long long Messaging.
The BYTE type, which is just an alias for unsigned char, is not an allowed type for UIntType parameter of
template<class Engine, std::size_t W, class UIntType>
class independent_bits_engine;
The standard, [rand.req.genl]/1.f, reads:
Throughout this subclause [rand], the effect of instantiating a template:
...
that has a template type parameter named UIntType is undefined unless the corresponding template argument is cv-unqualified and is one of unsigned short, unsigned int, unsigned long, or unsigned long long.
The answer from Evg is correct.
If you really want to have random bytes only, I would use a custom generator function that generates values between [-128, 127] or any desired range.
For instance:
#include <iostream>
#include <Windows.h>
#include <vector>
#include <random>
#include <algorithm>
#include <limits>
int main()
{
std::random_device r;
std::default_random_engine randomEngine(r());
std::uniform_int_distribution<int> uniformDist(CHAR_MIN, CHAR_MAX);
std::vector<BYTE> data(1000);
std::generate(data.begin(), data.end(), [&uniformDist, &randomEngine] () {
return (BYTE) uniformDist(randomEngine);
});
for (auto i : data) {
std::cout << int(i) << std::endl;
}
return 0;
}
References:
https://en.cppreference.com/w/cpp/numeric/random
https://en.cppreference.com/w/cpp/algorithm/generate
Just do this instead:
using random_bytes_engine = std::independent_bits_engine<std::default_random_engine, 32, uint32_t>;
Turns the engine into a 32-bit random number generator, but using it to initialize a vector of BYTEs works just fine.

How to convert tuple to byte array in c++11

I need to write a function to convert tuple to byte array.
The type of tuple may include int, long, double, std::string, char*,etc.
The size and type of tuple are arbitrary, such as
std:tuple<string, int, double> t1("abc", 1, 1.3);
or
std:tuple<char*, int, int, float, double, string> t2("abc", 1, 2, 1.3, 1.4, "hello");
I want use these tuple as input, and the byte array as return value. What should I do ?
There is also the brilliant C++ API for message pack which supports tuples natively
#include <string>
#include <sstream>
#include <tuple>
#include <msgpack.hpp>
int main() {
auto t = std::make_tuple("1", 1, 1.0);
auto buffer = std::stringstream{};
// easy peezy
msgpack::pack(buffer, t);
auto tuple_as_string = buffer.str();
}
You can use Boost Serialization for this task together with a small extension for std::tuple. However, it doesn't turn it into a byte array by default, but into something else. There is also binary_oarchive. Perhaps this fits your needs.
#include <fstream>
#include <tuple>
#include <boost/archive/text_oarchive.hpp>
#include "serialize_tuple.h" // https://github.com/Sydius/serialize-tuple
int main()
{
auto t = std::make_tuple(42,3.14,'a');
std::ofstream ofs("test.dat");
boost::archive::text_oarchive oa(ofs);
oa << t;
}

How to store a file name ext into a map using the experimental c++ 2017 lib

So i've got a simple little program that I want to store the file extensions into a map. The error comes when I try and store the d->path().extension(); into my map data.insert(d->path().extension(),15);. 15 is just a place holder for now I want to store the file ext as the key. I think the error is string is unknown to the std::experimental::filesystem.
This is the current error it throws:
"std::map<_Kty, _Ty, _Pr, _Alloc>::insert [with _Kty=std::string, _Ty=int, _Pr=std::less, _Alloc=std::allocator>]" matches the argument list
#include <map>
#include <regex>
#include <locale>
#include <iostream>
#include <fstream>
using namespace std;
#include <filesystem>
using namespace std::experimental::filesystem;
map<string,int> rscan2(path const& f,map<string, int> const& data, unsigned i = 0)
{
//string indet(i, ' ');
for (recursive_directory_iterator d(f), e; d != e; ++d)
{
data.insert(d->path().extension(),15);
if (is_directory(d->status()))
rscan2(d->path(), data, i + 1);
}
return data;
}
int main(int argc, char *argv[])
{
map<string, int> holdTheInfo;
rscan2(".", holdTheInfo);
}
path has many helper methods to convert to strings. Listing a few:
.string()
.generic_string()
.c_str()
operator string_type()
But the actual problem is that std::map::insert doesn't receive a key and value as arguments, only values. So you should instead use insert_or_assign (since C++17):
data.insert_or_assign(d->path().extension(), 15);
And the operator string_type() will be called for the returned path, converting it to an actual string.

Boost::Variant and function_types in it: How to put functions into Boost::variant?

Lyrics:
I try to implement a task pool over MPI. So I need some kind of RPC but one that would work between different parts of my program, meaning processor A wants processor B to call function C with argument D. We can not pass pointers to functions between processes like we do with threads, so we need some wrapper container to hold our function pointers at each process instance. All inside one source file\one program... So I started wondering about How to store functional objects with different signature in a container. My API Idea back then was wrong - it is better to define all functions in function pool at that pool construction (at least it shall be much easier to implement). But while implementing I faced next trouble:
Problem:
Such simple code (function_types, mpl::vector, variant):
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <string>
template <class T>
int append(T val)
{
std::cout << "hello";
return 0;
}
int main()
{
boost::variant<boost::function_types::function_type< boost::mpl::vector<int,int> >::type , boost::function_types::function_type< boost::mpl::vector<int,std::string> >::type > a;
return 0;
}
Will not compile falling with:
Error 1 error C2066: cast to function type is illegal c:\program files\boost\include\boost\variant\variant.hpp 1231 1
And looking at source we see:
this code block:
variant()
{
// NOTE TO USER :
// Compile error from here indicates that the first bound
// type is not default-constructible, and so variant cannot
// support its own default-construction.
//
new( storage_.address() ) internal_T0();
indicate_which(0); // zero is the index of the first bounded type
}
So I wonder: How to get around this error?
Also I tried:
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <iostream>
#include <string>
template <class T>
int append(T val)
{
std::cout << "hello";
return 1;
}
int main()
{
boost::variant< boost::function<int (std::string) >, boost::function<int (int) > > a;
a= &append<int>;
return 0;
}
Which fails with:
Error 1 error C2668: 'boost::detail::variant::make_initializer_node::apply<BaseIndexPair,Iterator>::initializer_node::initialize' : ambiguous call to overloaded function c:\program files\boost\include\boost\variant\variant.hpp 1330
Any Ideas on how to make boost.variant hold functions?
Of course we can play with shared pointers to functors like so:
#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <string>
template <class in, class out>
struct s_append
{
out operator()(in val) {
std::cout << "hello";
return out();
}
};
int main()
{
boost::variant<boost::shared_ptr<s_append<int, int> >, boost::shared_ptr< s_append<std::string, int> > > a;
boost::shared_ptr<s_append<int, int> > b(new s_append<int, int> );
a=b;
return 0;
}
and it would compile but resulting API sucks - you have to 1) create functors for all functions you want to use (meaning limit there use of current process scope); 2) use shared_pointers and so I don't really even get how to call functions nested that way (simple first guess (*a)(22); just won't compile =( and API starts to be as bad as we would have using Boost.Any).
Try inserting a dummy type as the first argument of the variant. As the comment you found explains, only the first type in the variant is used for the variant's own default constructor. You could use an empty struct type for this (struct NoFunction {};).
That said, you may have been onto something with the idea to use boost::functions as the types in the variant...they are default-constructible at least. I'm not sure what the other error you had from that approach was caused by, but just wanted to let you know you could pursue that angle more if you can't use the dummy-type workaround I mentioned.