C++ templates std::tuple to void* and back(C++模板std::tuple到VOID*并返回)
本文介绍了C++模板std::tuple到VOID*并返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在尝试使用C++11和各种模板创建一个资源管理器。问题是如何将std::tuple存储到集合并将其取回?在本例中,我尝试将其存储为VOID*(在此尽量不使用Boost::Any)。每次我转换回std::tuple时,我得到的强制转换的元组与从参数创建的元组相同(CurrentArgs==StoredArgs)。我认为下面的代码解释了一切。
http://ideone.com/h3yzvy
#include <memory>
#include <typeindex>
#include <iostream>
#include <string>
#include <vector>
#include <map>
typedef std::multimap<std::type_index, void*> Object;
typedef std::map<Object, std::shared_ptr<void>> ObjectCollection;
Object object;
ObjectCollection objectCollection;
template<typename T, typename... Args>
T* getResource(Args&& ... args)
{
// Creating tuple from the arguments
std::tuple<Args...> currentArgs(std::forward<Args>(args)...);
// Getting object type info
std::type_index type = { typeid(T) };
// Getting all objects from the collection that are of the same type
auto range = object.equal_range(type);
for (auto it = range.first; it != range.second; ++it)
{
// it->second is a void* Since we are iterating through
// the the collection of the same type I'm trying to cast
// back. Object construct parameters should be the same
// (in this example: const std::string &fileName)
auto storedArgs = *static_cast<std::tuple<Args...>*>(it->second);
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Problem is here. currentArgs and storedArgs are always equal :/
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Return the object from the collection if current arguments and
// arguments from the collection are the same
if (currentArgs == storedArgs)
{
std::cout << "Found... returning..." << std::endl;
// found... return...
return static_cast<T*>(objectCollection[object].get());
}
}
// Object with the same arguments were not found
// Adding to collection and return
std::cout << "Adding to collection..." << std::endl;
object.emplace(type, ¤tArgs);
objectCollection[object] = std::make_shared<T>(std::forward<Args>(args)...);
return static_cast<T*>(objectCollection[object].get());
}
class Resource
{
public:
virtual ~Resource() = default;
template<typename T, typename... Args>
static T* get(Args&& ... args)
{
return getResource<T>(std::forward<Args>(args)...);
}
};
class Image
{
public:
Image(const std::string &fileName)
{
std::cout << "Loading image " << fileName.c_str() << std::endl;
}
~Image(){};
};
int main()
{
auto image1 = Resource::get<Image>("aaa.jpg");
auto image2 = Resource::get<Image>("bbb.jpg");
auto image3 = Resource::get<Image>("aaa.jpg");
getchar();
}
编辑
感谢大家的投入。如果有人关心我的最终资源.h看起来像这样,并且工作完美:
#pragma once
#include <memory>
#include <map>
template<class T, class...Args>
std::map<std::tuple<Args...>, std::shared_ptr<T>>& getCache()
{
static std::map<std::tuple<Args...>, std::shared_ptr<T>> cache; // only run once
return cache;
}
template<typename T, typename... Args>
std::shared_ptr<T> getResource(Args&& ... args)
{
// std::decay_t should be used
auto& cache = getCache<T, std::decay_t<Args>...>();
// Creating tuple from the arguments
auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
// Search for object in the cache
auto it = cache.find(arguments);
if (it != cache.end())
{
// Found. Return.
return it->second;
}
// Not found. Add to cache.
auto object = std::make_shared<T>(std::forward<Args>(args)...);
cache.emplace(std::make_pair(std::move(arguments), object));
return object;
}
class Resource
{
public:
virtual ~Resource() = default;
template<typename T, typename... Args>
static std::shared_ptr<T> get(Args&& ... args)
{
return getResource<T>(std::forward<Args>(args)...);
}
};
推荐答案
为什么不针对每个类型和参数使用一个函数本地映射? 由于您已经按照以下两个条件过滤数据,因此可以简化代码:
#include <iostream>
#include <math.h>
using namespace std;
#include <memory>
#include <typeindex>
#include <iostream>
#include <string>
#include <vector>
#include <map>
template<typename T, typename... Args>
std::shared_ptr<T> getResource(Args&& ... args)
{
static std::map<std::tuple<Args...>, std::shared_ptr<T>> objectCollection;
// Creating tuple from the arguments
std::tuple<Args...> currentArgs(std::forward<Args>(args)...);
//Search for object in map
auto objectIter = objectCollection.find(currentArgs);
if(objectIter != objectCollection.end())
{
std::cout << "Found... returning..." << std::endl;
return objectIter->second;
}
std::shared_ptr<T> newObject(new T(args...));
std::cout << "Adding to collection..." << std::endl;
objectCollection.insert(std::pair<std::tuple<Args...>, std::shared_ptr<T>>(currentArgs, newObject));
return newObject;
}
class Resource
{
public:
virtual ~Resource() = default;
template<typename T, typename... Args>
static std::shared_ptr<T> get(Args&& ... args)
{
return getResource<T>(std::forward<Args>(args)...);
}
};
class Image
{
public:
Image(const std::string &fileName)
{
std::cout << "Loading image " << fileName.c_str() << std::endl;
}
~Image() {};
};
int main()
{
auto image1 = Resource::get<Image>("aaa.jpg");
auto image2 = Resource::get<Image>("bbb.jpg");
auto image3 = Resource::get<Image>("aaa.jpg");
getchar();
}
编辑:我还将代码更改为始终使用SHARED_PTR。
这篇关于C++模板std::tuple到VOID*并返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
沃梦达教程
本文标题为:C++模板std::tuple到VOID*并返回
基础教程推荐
猜你喜欢
- C++ 程序在执行 std::string 分配时总是崩溃 2022-01-01
- 调用std::Package_TASK::Get_Future()时可能出现争用情况 2022-12-17
- C++,'if' 表达式中的变量声明 2021-01-01
- 如何在 C++ 中处理或避免堆栈溢出 2022-01-01
- 运算符重载的基本规则和习语是什么? 2022-10-31
- C++ 标准:取消引用 NULL 指针以获取引用? 2021-01-01
- 如何定义双括号/双迭代器运算符,类似于向量的向量? 2022-01-01
- 设计字符串本地化的最佳方法 2022-01-01
- 什么是T&&(双与号)在 C++11 中是什么意思? 2022-11-04
- 您如何将 CreateThread 用于属于类成员的函数? 2021-01-01