c++ - 如何改变模板的可变参数
问题描述
我正在尝试创建一个数组结构:
auto x = MakeMegaContainer<StructA, StructB, StructC>();
我想在编译时生成如下结构:
struct MegaContainer {
std::tuple< Container<StructA>, Container<StructB>, Container<StructC> > Data;
};
创建方法是不可协商的,我认为元组是最好的方法,因为稍后我可以使用 访问一个容器的结构元素std::get<StructA>(x)[index]
,如果我的容器允许的话[]
。
我尝试做类似的事情:
template<typename... LilStructs>
class StructStorage {
public:
template<typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Get(id); // Get is defined for MyContainer
}
template<typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Contains(id); // Contains is defined for MyContainer
}
private:
std::tuple<MyContainer<LilStructs>...> m_Storage;
};
但我认为这行不通。我不确定如何获取可变参数并用容器“包装”它们
我应该怎么做?
后续问题:MyContainer
还需要自定义它的其他参数,例如最大尺寸。有没有一种很好的方法来传递它,比如template<typename... LilStructs, uint64_t MAX_SIZE=4096>
?
这是容器的精简版本,用于一个最小的可重现示例:
template<typename T_elem, typename T_int = uint64_t, T_int MAX_SIZE = 4096>
class MyContainer{
public:
MyContainer() = default;
~MyContainer() = default;
bool Contains(const T_int& id) const;
T_elem& operator[](const T_int& id);
T_elem& Get(const T_int& id);
private:
std::map<T_int, T_elem> m_Map;
T_int m_Size = 0;
};
template<typename T_elem, typename T_int, T_int MAX_SIZE>
bool MyContainer<T_elem, T_int, MAX_SIZE>::Contains(
const T_int& id
) const {
return m_Map[id] < m_Size;
}
template<typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::operator[](const T_int& id) {
return m_Map[id];
}
template<typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::Get(const T_int& id) {
return operator[](id);
}
当我尝试编译时:
void Test() {
struct SA { int x; };
struct SB { float x; };
struct SC { char x; };
auto& tests = StructStorage <SA, SB, SC>();
bool x = !tests.ContainsStruct<SA>(5);
}
我得到错误:
c:\...\test.h(18): error C2039: 'Contains': is not a member of 'Trial::SA'
正如我所说,我知道错误std::tuple<MyContainer<LilStructs>...> m_Storage;
在行中,并且错误与执行无关MyContainer
(前提是Contains
并且Get
已执行),但我不知道用什么替换它,或者如何实现我正在寻找的功能(已经描述过)。
解决方案
看这部分:
template <typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Get(id); // Get is defined for MyContainer
}
template <typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Contains(id); // Contains is defined for MyContainer
}
m_Storage
元组是MyContainer<LilStructs>...
s 而不是s的元组LilStructs...
所以你真正想要做的是:
template <typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Get(id); // Get is defined for MyContainer
// ^^^^^^^^^^^^^^^^^^^^^^
}
template <typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Contains(id); // Contains is defined for MyContainer
// ^^^^^^^^^^^^^^^^^^^^^^
}
另外,你的Contains()
功能是错误的。用这个:
template <typename T_elem, typename T_int, T_int MAX_SIZE>
bool MyContainer<T_elem, T_int, MAX_SIZE>::Contains(const T_int& id) const {
return m_Map.find(id) != m_Map.end();
}
完整的工作代码:
#include <cstdint>
#include <cassert>
#include <tuple>
#include <map>
template <typename T_elem, typename T_int = uint64_t, T_int MAX_SIZE = 4096>
class MyContainer{
public:
MyContainer() = default;
~MyContainer() = default;
bool Contains(const T_int& id) const;
T_elem& operator[](const T_int& id);
T_elem& Get(const T_int& id);
private:
std::map<T_int, T_elem> m_Map;
T_int m_Size = 0;
};
template <typename T_elem, typename T_int, T_int MAX_SIZE>
bool MyContainer<T_elem, T_int, MAX_SIZE>::Contains(const T_int& id) const {
return m_Map.find(id) != m_Map.end();
}
template <typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::operator[](const T_int& id) {
return m_Map[id];
}
template <typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::Get(const T_int& id) {
return operator[](id);
}
template <typename ...LilStructs>
class StructStorage {
public:
template <typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Get(id);
}
template <typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Contains(id);
}
private:
std::tuple<MyContainer<LilStructs>...> m_Storage;
};
int main() {
struct SA { int x; };
struct SB { float x; };
struct SC { char x; };
auto tests = StructStorage<SA, SB, SC>();
assert(!tests.ContainsStruct<SA>(5));
}
推荐阅读
- javascript - 如何在 phpMyAdmin 的世界地图上显示人口统计数据?
- mongodb - 在 Handlebars 304 错误中嵌套 {{#each}}
- reactjs - 当我单击仪表板中的菜单时,React 路由器显示空白页面
- java - 为什么直接同步一个 ArrayList 可以确保它对其他线程的可见性
- c# - 使用 C# 的类型(反射)是不好的做法吗?
- windows - 使用 PowerShell 创建 Windows 计划任务时停止现有实例选项
- python - 如何在 Python 中模拟一系列用户输入
- mariadb - MariaDB 的默认端口号是多少?
- html - 一个小小的 CSS 边距问题
- matlab - Matlab中MFCC系数的一阶导数