如何改变模板的可变参数
How to mutate variadic arguments of a template
我正在尝试创建一个数组结构:
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>...
而不是 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));
}
我正在尝试创建一个数组结构:
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>...
而不是 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));
}