unordered_map with string in managed_shared_memory fails - boost

This is my code:
int main (int argc, char *argv[])
{
typedef int KeyType;
typedef string MappedType;
typedef std::pair<KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmAlloc;
typedef boost::unordered_map<KeyType, MappedType, boost::hash<KeyType>, std::equal_to<KeyType>, ShmAlloc> ShmHashMap;
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_or_create, "ContainerSharedMemory", 65536);
if(argc == 2 && string(argv[1]) == "clear")
{
boost::interprocess::shared_memory_object::remove("ContainerSharedMemory");
return 0;
}
ShmHashMap *hash_map = segment.find_or_construct<ShmHashMap>(boost::interprocess::unique_instance)(segment.get_segment_manager());
if(hash_map == NULL)
{
cout << "find_or_construct error" << endl;
return 0;
}
for(int i = 0; i < 5; ++i) {
ShmHashMap::iterator iter = hash_map->find(i);
if (iter == hash_map->end()) {
hash_map->insert(ValueType(i, "test"));
}
}
cout << "all..." << endl;
for(ShmHashMap::iterator iter = hash_map->begin(); iter != hash_map->end(); ++iter)
{
cout << iter->first << "|" << iter->second << endl;
}
cout << "end..." << endl;
return 0;
}
Everything is ok when MappedType is int, but a segment fault whit this code like this:
Rerun this program to access hash map in shared memory will coredump
----------------------------edit again----------------------------------
the problem about string is solved by sehe, thank you
and if i design a template class want to hide that detail, how could i do? if there is some perfect way
template<typename MappedType>
struct ComplexMappedType
{
ComplexMappedType(): t_access(0), t_expire(0) {}
ComplexMappedType(const MappedType& v, uint32_t a, uint32_t e): value(v), t_access(a), t_expire(e) {}
MappedType value;
uint32_t t_access;
uint32_t t_expire;
};
template <typename KeyType, typename MappedType>
class MMSHashMap
{
private:
typedef ComplexMappedType<MappedType> DataType;
typedef std::pair<KeyType, DataType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmAlloc;
typedef boost::unordered_map<KeyType, DataType, boost::hash<KeyType>, std::equal_to<KeyType>, ShmAlloc> ShmHashMap;
public:
MMSHashMap(const std::string& name, size_t size, float e_thr, float e_scale);
~MMSHashMap() {delete pMemorySegment;}
size_t getMEMSize() { return pMemorySegment->get_size(); }
size_t getMEMFreeSize() { return pMemorySegment->get_free_memory(); }
bool get(const KeyType& key, MappedType& value, uint32_t& expire);
bool set(const KeyType& key, const MappedType& value, uint32_t expire);
bool del(const KeyType& key);
private:
void doCapacityElimination();
std::string _name;
boost::interprocess::managed_shared_memory* pMemorySegment;
boost::shared_mutex mutex, mutex_eliminate;
float fEliminateThreshold, fEliminateScale;
};

Of course. std::string allocates from the heap.
The heap is in your process address space, so any other process reading the same shared memory is going to get a wrong raw pointer there and invoke UB.
You need to use a shared-memory allocator with the strings too.
Live On Coliru (using mapped file for Coliru)
With shared memory:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/string.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>
namespace bip = boost::interprocess;
int main (int argc, char *argv[])
{
typedef int KeyType;
typedef boost::container::basic_string<char, std::char_traits<char>, bip::allocator<char, bip::managed_shared_memory::segment_manager> > MappedType;
typedef std::pair<KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmAlloc;
typedef boost::unordered_map<KeyType, MappedType, boost::hash<KeyType>, std::equal_to<KeyType>, boost::container::scoped_allocator_adaptor<ShmAlloc> > ShmHashMap;
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_or_create, "ContainerSharedMemory", 65536);
if(argc == 2 && std::string(argv[1]) == "clear")
{
boost::interprocess::shared_memory_object::remove("ContainerSharedMemory");
return 0;
}
ShmHashMap *hash_map = segment.find_or_construct<ShmHashMap>(boost::interprocess::unique_instance)(segment.get_segment_manager());
if(hash_map == NULL)
{
std::cout << "find_or_construct error" << std::endl;
return 0;
}
for(int i = 0; i < 5; ++i) {
ShmHashMap::iterator iter = hash_map->find(i);
if (iter == hash_map->end()) {
hash_map->insert(ValueType(i, MappedType { "hello", segment.get_segment_manager() }));
}
}
std::cout << "all..." << std::endl;
for(ShmHashMap::iterator iter = hash_map->begin(); iter != hash_map->end(); ++iter)
{
std::cout << iter->first << "|" << iter->second << std::endl;
}
std::cout << "end..." << std::endl;
}
Prints
all...
4|hello
3|hello
2|hello
1|hello
0|hello
end...

Related

Begin was not declared in the scope for Generic Array Template Class

#include <iostream>
#include <string>
template <typename T, int N>
class Array {
int size{N};
T values{N};
friend std::ostream &operator<<(std::ostream &os, const Array<T, N> &arr) {
os << "[";
for (const auto &val: arr.values)
os << val << " ";
os << "]" << std::endl;
return os;
}
public:
Array() = default;
Array(T value_added) {
for(auto &value: values)
value = value_added;
}
void fill(T data_value) {
for (auto &value: values)
value = data_value;
}
int get_size() const {
return size;
}
T &operator[](int index) {
return values[index];
}
};
int main () {
Array<int,2> nums;
std::cout << "The size of nums is: " << nums.get_size() << std::endl;
std::cout << nums << std::endl;
}
I am trying to create a generic array template class but I get the error Begin was not declared in the scope and it says it is due to the for (const auto &val: arr.values) loop.

Why a member function in a class template creates the same object in the same address

I am working on testing a lock-free work-stealing queue I wrote recently. However, I found a weird issue, that when I push a new item to the queue, it only returns me the same object that was pushed at the last. It took me one day and I still cannot figure out why this happened.
This is the output, every time, the data is the same to be pushed to the queue, which is why I only have the last result being 45, it should be all 45 for the 4 res items. Anybody can help me here :(
push_back addr: 0x21d3ea0 bk: 0 &data: 0x7ffe36802380
push_back addr: 0x21d3ea4 bk: 0 &data: 0x7ffe36802380
push_back addr: 0x21d3ea8 bk: 0 &data: 0x7ffe36802380
push_back addr: 0x21d3eac bk: 0 &data: 0x7ffe36802380
res[0]=-1
res[1]=-1
res[2]=-1
res[3]=45
Below is the simplified code:
#include <memory>
#include <functional>
#include <type_traits>
class FunctionWrapper {
private:
class ImplInterface {
public:
virtual void invoke() = 0;
virtual ~ImplInterface() {}
};
std::unique_ptr<ImplInterface> impl;
template <typename F, typename... Args>
class Impl : public ImplInterface {
private:
std::function<void()> callBack;
public:
Impl(F&& f_, Args&&... args_) {
callBack = [&f_, &args_...]() { f_(std::forward<Args>(args_)...); };
}
void invoke() override { callBack(); }
};
public:
template <typename F, typename... Args>
FunctionWrapper(F&& f_, Args&&... args_) : impl(new Impl<F, Args...>(std::forward<F>(f_), std::forward<Args>(args_)...)) {}
void operator()() { impl->invoke(); }
FunctionWrapper() = default;
FunctionWrapper(FunctionWrapper&& other) : impl(std::move(other.impl)) {}
FunctionWrapper& operator=(FunctionWrapper&& other) {
impl = std::move(other.impl);
return *this;
}
FunctionWrapper(const FunctionWrapper&) = delete;
FunctionWrapper(FunctionWrapper&) = delete;
FunctionWrapper& operator=(const FunctionWrapper&) = delete;
};
#include <atomic>
#include <array>
#include <iostream>
#include "functionwrapper.h"
class LockFreeWorkStealingQueue {
private:
using DataType = FunctionWrapper;
static constexpr auto DEFAULT_COUNT = 2048u;
static constexpr auto MASK = DEFAULT_COUNT - 1u;
std::array<DataType, DEFAULT_COUNT> q;
unsigned int ft{0};
unsigned int bk{0};
public:
LockFreeWorkStealingQueue() {}
LockFreeWorkStealingQueue(const LockFreeWorkStealingQueue&) = delete;
LockFreeWorkStealingQueue& operator=(const LockFreeWorkStealingQueue&) = delete;
void push_back(DataType data) {
std::cout << "bk: " << (bk&MASK) << " &data: " << &data << std::endl;
q[bk & MASK] = std::move(data);
bk++;
}
bool try_pop_back(DataType& res) {
if (bk > ft) {
res = std::move(q[(bk - 1) & MASK]);
bk--;
return true;
}
return false;
}
};
#include "lockfreeworkstealingqueue.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <cassert>
#include <vector>
constexpr unsigned int NUM = 4;
void sumOver(const std::vector<int>& v, int& res) {
res = std::accumulate(v.begin(), v.end(), 0);
//std::cout << "call sumOver, res = " << res << std::endl;
//std::cout << "call sumOver, addr: " << &res << std::endl;
}
int main () {
std::vector<int> v { 1,2,3,4,5,6,7,8,9 };
std::vector<int> res(NUM, -1);
std::vector<LockFreeWorkStealingQueue> wsq(4);
{
for (auto i = 0; i < 4; ++i) {
for (auto j = 0; j < NUM / 4; ++j) {
std::cout << "push_back addr: " << &res[i*(NUM/4)+j] << std::endl;
wsq[i].push_back(FunctionWrapper(sumOver, std::ref(v), std::ref(res.at(i*(NUM/4)+j))));
}
}
FunctionWrapper f;
for (auto i = 0; i < 4; ++i) {
for (auto j = 0; j < NUM / 4; ++j) {
if(wsq[i].try_pop_back(f)) {
f();
}
}
}
}
for (auto i = 0; i < 4; ++i) {
for (auto j = 0; j < NUM / 4; ++j) {
std::cout << "res[" << i*(NUM/4)+j << "]=" << res[i*(NUM/4)+j] << std::endl;
}
}
return 0;
}
EDIT: I made a change to functionwrapper.h to refect on the comments. and now it works well.
#include <memory>
#include <functional>
class FunctionWrapper {
private:
std::function<void()> callback;
public:
template <typename F, typename... Args>
FunctionWrapper(F&& f_, Args&&... args_) : callback([f_, args_...]() { f_(args_...); }) {}
void operator()() { callback(); }
FunctionWrapper() = default;
FunctionWrapper(FunctionWrapper&& other) : callback(std::move(other.callback)) {}
FunctionWrapper& operator=(FunctionWrapper&& other) {
callback = std::move(other.callback);
return *this;
}
FunctionWrapper(const FunctionWrapper&) = delete;
FunctionWrapper(FunctionWrapper&) = delete;
FunctionWrapper& operator=(const FunctionWrapper&) = delete;
};
The lambda in FunctionWrapper::Impl captures references to temporary std::reference_wrapper instances (produced by std::ref calls in main). By the time the lambda is actually called, those temporaries have long been destroyed and the references are dangling. Whereupon your program exhibits undefined behavior, by way of accessing objects whose lifetime has ended.
You want to capture by value instead, as in
Impl(F&& f_, Args&&... args_) {
callBack = [f_, args_...]() { f_(args_...); };
}
Demo

Protobuf ParseFromZeroCopyStream incurs high memory usage with repeated field

I have encountered a problem of high memory usage when using ParseFromZeroCopyStream to load file in which a large buffer is written. Besides, the code snippet below uses 60Gb++ of RAM but failed as the system froze after reaching its RAM limit.
FYI, I am using protobuf as DLL.
scene.proto
syntax = "proto3";
package Recipe;
option cc_enable_arenas = true;
message Scene
{
repeated int32 image_data = 1 [packed=true];
}
source.cpp
#include <iostream>
#include <fstream>
#include <ostream>
#include <istream>
#include <string>
#include <cstdint>
#include "Scene.pb.h"
#include <google\protobuf\io\zero_copy_stream_impl.h>
#include <google\protobuf\io\gzip_stream.h>
#include <google\protobuf\arena.h>
int const _MIN = 0;
int const _MAX = 255;
unsigned int const _SIZE = 1280000000;
//unsigned int const _SIZE = 2000;
unsigned int const _COMPRESSION_LEVEL = 6;
void randWithinUnsignedCharSize(uint8_t * buffer, unsigned int size)
{
for (size_t i = 0; i < size; ++i)
{
buffer[i] = i;
}
}
using namespace google::protobuf::io;
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
google::protobuf::Arena arena;
Recipe::Scene * scene = google::protobuf::Arena::CreateMessage<Recipe::Scene>(&arena);
uint8_t * imageData = new uint8_t[_SIZE];
randWithinUnsignedCharSize(imageData, _SIZE);
scene->mutable_image_data()->Resize(_SIZE, 0);
for (size_t i = 0; i < _SIZE; i++)
{
scene->set_image_data(i, imageData[i]);
}
std::cout << "done saving data to repeated field.\n";
{
std::fstream output("data.txt", std::ios::out | std::ios::trunc | std::ios::binary);
OstreamOutputStream outputFileStream(&output);
GzipOutputStream::Options options;
options.format = GzipOutputStream::GZIP;
options.compression_level = _COMPRESSION_LEVEL;
GzipOutputStream gzipOutputStream(&outputFileStream, options);
if (!scene->SerializeToZeroCopyStream(&gzipOutputStream)) {
std::cerr << "Failed to write scene." << std::endl;
return -1;
}
}
delete[] imageData;
}
std::cout << "Finish serializing into data.txt\n";
{
google::protobuf::Arena arena1;
Recipe::Scene * scene1 = google::protobuf::Arena::CreateMessage<Recipe::Scene>(&arena1);
{
std::fstream input("data.txt", std::ios::in | std::ios::binary);
IstreamInputStream inputFileStream(&input);
GzipInputStream gzipInputStream(&inputFileStream);
if (!scene1->ParseFromZeroCopyStream(&gzipInputStream)) {
std::cerr << "Failed to parse scene." << std::endl;
return -1;
}
}
std::cout << "scene1->imagedata_size() " << scene1->image_data_size() << std::endl;
}
google::protobuf::ShutdownProtobufLibrary();
return 0;
}

how would I go about handling these return type errors? (hashmap/table)

#ifndef HASHMAP_H
#define HASHMAP_H
#include <iostream>
#include <string>
#include <vector>
using namespace std;
enum Status{open , active, deactivated };
//template <typename T>
template</*typename Key,*/ typename T>
class hashmap{
private:
class Node{
public:
const string Key;
//vector<T> values;
T value;
Status status;
Node(string key, T val) :Key(key), value(val), status(active){}
void operator =(const Node &n){
string *ptr;
ptr = (string*)(&(this->Key));
*ptr = n.Key;
//Node(n);
this->status = n.status;
this->value = n.value;
}
Node() :status(open){}
Node(const string& key) :Key(key), status(active){}
//Node(const Node &n) : value(n.val), status(n.status){}
};
//typedef map<
unsigned int hash(const string& s, int tableSize){
unsigned int h = 0;
/*each(s)*/
for(auto it : s) h = 31 * h + unsigned(it);
return h % tableSize;
}
unsigned int hash(const string& s){
return hash(s, table_size);
}
int table_size = 103;
vector<Node> table;
typedef typename vector<Node>::iterator iter;
public:
//default constructor
hashmap(){
table = vector<Node>(table_size);
}
//copy constructor
hashmap(const hashmap& x){
table = x.table;
//for (auto it = )
}
//assignment operator //has been removed
hashmap& operator=(const hashmap& x){
this->table.erase(this->table.begin(), this->table.begin() + 103);
for ( int i = 0; i < x.table_size; i++){
this->table.push_back(x.table.at(i));
}
return *this;
}
//destructor
~hashmap(){
table.clear();
}
//index operator
T& operator[](const string x){
int h = hash(x, table.size());
if (table[h].Key == x){
return (table[h].value);
}
else {
Node* n = new Node(x);
table[h] = *n;
return (table[h].value);
}
}
//Node test
void okay(const string x,int i){
Node *temp = new Node(x, i);
cout << temp->status << endl;
/*cout << table[1].status << endl;
cout << table[2].status << endl;
table.at(0) = (*temp);
cout << table[0].Key << endl;
cout << table[0].value << endl;
cout << table[3].status << endl;*/
}
int stride(int x){
return (7-x%7);
}
//find()
iter find(const string& x){
int h = hash(x);
int s = stride(h);
int t = table_size;
int z;
//for (int i = 0; i < t; i++){
for (int i = hash(x, table_size) % t; i != t; i = (i + stride(h)) % t){
z = (h + i*s) % table_size;
if (table[z].status == open) return NULL;
if (table[z].status == deactivated) continue;
if (table[z].Key == x) return &table[h];
}
return table.end();
}
//begin()
iter begin(){
return table.begin();
}
//end()
iter end(){
return table.end();
}
};
#endif // !HASHMAP_H
Everything seems to be working fine except the find function. It's suppose to probe through the vector and return values upon conditions but the problem I'm having is I get these errors about return type conflicts.
Error2error C2664: 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap::Node>>>::_Vector_iterator(const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap::Node>>> &)' : cannot convert argument 1 from 'hashmap<int>::Node *' to 'const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>> &'
Error1error C2664: 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>>::_Vector_iterator(const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>> &)' : cannot convert argument 1 from 'int' to 'const
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<hashmap<int>::Node>>> &'
How can I edit the iterator to fix this?
thank you.

Storing function pointers with different types c++ boost::bind

I have dug around quite a bit today and have come up empty. Is there any way to store a functor that is returned from a boost::bind with different types? I found an example that used boost::variants but not sure that this is needed. (Foo and Bar have been simplified for simplicity sake)
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <map>
#include <iostream>
template <typename FooType>
struct Foo {
const FooType tmp_value;
Foo(const FooType& tmp_) :
tmp_value(tmp_)
{
}
template<typename Object>
void operator()(Object& operand)
{
std::cout << operand << std::endl;
operand += tmp_value;
}
};
template <typename BarType>
struct Bar {
const BarType tmp_value;
Bar(const BarType& tmp_) :
tmp_value(tmp_)
{
}
template<typename Object>
void operator()(Object& operand)
{
std::cout << operand << std::endl;
operand -= tmp_value;
}
};
typedef boost::variant<
boost::function<void(int32_t)>,
boost::function<void(int64_t)>,
boost::function<void(double)>,
boost::function<void(float)>
> my_functions;
typedef std::map<std::string, my_functions> test_map;
enum test_t {
FOO,
BAR
};
test_map createFunMap() {
test_map result;
for(int i = 0; i < 2; i++) {
switch(i) {
case test_t::FOO: {
std::cout << "In FOO" << std::endl;
Foo<double> p(1.0);
result.insert(std::pair<std::string,
boost::function<void(double)>>
("foo", boost::bind<void>(p, _1)));
break;
}
case test_t::BAR: {
std::cout << "In BAR" << std::endl;
Bar<int32_t> p(1.0);
result.insert(std::pair<std::string,
boost::function<void(int32_t)>>
("bar", boost::bind<void>(p, _1)));
break;
}
default:
std::cout << "just a default" << std::endl;
break;
}
}
return result;
}
int main() {
test_map myMap;
double t = 5.0;
myMap = createFunMap();
std::cout << t << std::endl;
myMap["foo"](t);
std::cout << t << std::endl;
return 0;
}
compiler output:
g++ -Wall --std=c++0x -I. test_ptrs.cc -o test_ptrs
test_ptrs.cc:93:2: error: type 'mapped_type' (aka 'boost::variant<boost::function<void (int)>, boost::function<void (long long)>, boost::function<void (double)>, boost::function<void (float)>,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>') does not provide a call operator
myMap["foo"](t);
^~~~~~~~~~~~
1 error generated.
Thanks.
You have polymorphic functors (Foo and Bar).
You want to type erase them for a certain set of operand types. I suggest defining a type-erased functor type for the purpose:
struct ErasedFunctor
{
template<typename F> ErasedFunctor(F&& f)
: pimpl(new impl_<F>(std::forward<F>(f))) {}
template <typename T>
void operator()(T& oper) const {
assert(pimpl);
pimpl->call(oper);
}
private:
typedef boost::variant<int32_t&, int64_t&, double&, float&> Operand;
struct base_ { virtual void call(Operand oper) const = 0; };
// struct impl_ : base_ ...
std::shared_ptr<base_> pimpl;
};
Now you can simply store the function objects directly in the map:
typedef std::map<std::string, ErasedFunctor> test_map;
test_map createFunMap() {
return test_map {
{ "foo", Foo<double>(1.0) },
{ "bar", Bar<int32_t>(1) },
};
}
Let's use at("foo") instead of ["foo"] to avoid having to make ErasedFunctor default-constructible:
int main() {
test_map myMap = createFunMap();
double t = 5.0;
std::cout << t << std::endl;
myMap.at("foo")(t);
std::cout << t << std::endl;
myMap.at("bar")(t);
std::cout << t << std::endl;
}
Prints
5
void ErasedFunctor::apply::operator()(const F&, T&) const [with F = Foo<double>; T = double](5)
5
6
void ErasedFunctor::apply::operator()(const F&, T&) const [with F = Bar<int>; T = double](6)
6
5
See it Live On Coliru
For more background see:
Generating an interface without virtual functions?
Full Sample
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <iostream>
template <typename FooType> struct Foo {
const FooType tmp_value;
Foo(const FooType &tmp_) : tmp_value(tmp_) {}
template <typename Object> void operator()(Object &operand) const {
std::cout << operand << std::endl;
operand += tmp_value;
}
};
template <typename BarType> struct Bar {
const BarType tmp_value;
Bar(const BarType &tmp_) : tmp_value(tmp_) {}
template <typename Object> void operator()(Object &operand) const {
std::cout << operand << std::endl;
operand -= tmp_value;
}
};
struct ErasedFunctor
{
template<typename F> ErasedFunctor(F&& f)
: pimpl(new impl_<F>(std::forward<F>(f))) {}
template <typename T>
void operator()(T& oper) const {
assert(pimpl);
pimpl->call(oper);
}
private:
typedef boost::variant<int32_t&, int64_t&, double&, float&> Operand;
struct base_ { virtual void call(Operand oper) const = 0; };
struct apply : boost::static_visitor<void> {
template <typename F, typename T> void operator()(F const& f, T& v) const {
std::cout << __PRETTY_FUNCTION__ << "(" << v << ")\n";
f(v);
}
};
template <typename F> struct impl_ : base_ {
F f_;
impl_(F&& f) : f_(std::forward<F>(f)) { }
virtual void call(Operand oper) const override {
boost::apply_visitor(boost::bind(apply(), boost::cref(f_), _1), oper);
}
};
std::shared_ptr<base_> pimpl;
};
#include <map>
typedef std::map<std::string, ErasedFunctor> test_map;
test_map createFunMap() {
return test_map {
{ "foo", Foo<double>(1.0) },
{ "bar", Bar<int32_t>(1) },
};
}
int main() {
test_map myMap = createFunMap();
double t = 5.0;
std::cout << t << std::endl;
myMap.at("foo")(t);
std::cout << t << std::endl;
myMap.at("bar")(t);
std::cout << t << std::endl;
}

Resources