提问人:dkoch 提问时间:6/26/2023 最后编辑:JeJodkoch 更新时间:6/27/2023 访问量:160
如何根据类型更改/设置模板参数?
How to change/set template parameter based on type?
问:
我想创建一个静态类,它将充当固定大小的内存分配器。
让我们看一下这个简化的例子:
struct A {};
struct B {};
template<class T, std::size_t MaxNumObjects>
class InternalContainer
{
public:
static constexpr std::size_t maxObjects = MaxNumObjects;
static T* createObject()
{
return ::new(&objects[idx++]) T;
}
static T* releaseObject() { /*...*/ };
private:
using buffer_t = std::aligned_storage_t<sizeof(T), alignof(T)>;
static buffer_t objects[maxObjects];
static std::size_t idx;
};
A* a = InternalContainer<A, 2>::createObject();
B* b = InternalContainer<B, 5>::createObject();
如何根据类型预定义容器的最大大小?
// will be replaced "InternalContainer<A, 2>"
A* a = MyContainer<A>::createObject();
// will be replaced "InternalContainer<B, 5>"
B* b = MyContainer<B>::createObject();
我尝试过这样的事情,但它不起作用:
template<class T>
using MyContainer = InternalContainer<A, 2>;
template<class T>
using MyContainer = InternalContainer<B, 5>;
答:
8赞
JeJo
6/26/2023
#1
如何根据类型预定义容器的最大大小?
您在这里有几个选择。
最简单的方法是为默认类型(即 ,A
B
)
template <class T> struct MyContainer;
// specialization for A
template <> struct MyContainer<A> {
using type = InternalContainer<A, 2>;
};
// specialization for B
template <> struct MyContainer<B> {
using type = InternalContainer<B, 5>;
};
// ... so on!
// Helper alias
template <class T>
using MyContainer_t = typename MyContainer<T>::type;
static_assert(std::is_same_v<MyContainer_t<A>, InternalContainer<A, 2>>);
或者,使用 if constexpr
(需要 c++17 或更高版本),您可以执行如下操作:
#include <type_traits>
template <class T>
constexpr auto typeHelper()
{
// following requires the InternalContainer<T, N> be default constructible!!
if constexpr (std::is_same_v<T, A>) return InternalContainer<A, 2>{};
else if constexpr (std::is_same_v<T, B>) return InternalContainer<B, 5>{};
}
template <class T>
using MyContainer = decltype(typeHelper<T>());
A* a = MyContainer<A>::createObject(); // will be replaced b InternalContainer<A, 2>
B* b = MyContainer<B>::createObject(); // will be replaced b InternalContainer<B, 5>
或者,使用 std::conditional_t
您也可以这样做
#include <type_traits> // std::conditional_t
template <class T>
using MyContainer = std::conditional_t<std::is_same_v<T, A>, InternalContainer<A, 2>,
std::conditional_t<std::is_same_v<T, B>, InternalContainer<B, 5>,
/*Default case if types are not A nor B*/ void>
>;
评论
0赞
dkoch
6/27/2023
感谢您展示解决此问题的不同方法
0赞
Marek R
6/27/2023
if constexpr
解决方案很糟糕,因为代码不可扩展。基本上需要知道所有应该有自定义尺寸的类型。事实上,这里的所有解决方案都有这个很大的缺点。typeHelper
2赞
LernerCpp
6/27/2023
@MarekR 为什么这里的 if constexpr 不好?顺便说一句,我看到解决方案或多或少地显示了 OP,根据他/她提出的要求,多种替代方案。
1赞
Marek R
6/27/2023
问题在于您的实现依赖于 和 。因此,如果此代码的用户想要为其他未知类自定义项目数,他必须修改您的代码以添加 .这违反了开盘原则。在其他答案中,您可以提供专业化,而不必触摸实现细节。A
B
X
if
X
6赞
Turtlefight
6/27/2023
#2
这可以通过显式专用化变量模板轻松实现,例如:
struct A {};
struct B {};
struct C {};
// default size for all InternalContainers
template<class T>
constexpr std::size_t InternalContainerDefaultSize = 64;
// specialization for A
template<>
constexpr std::size_t InternalContainerDefaultSize<A> = 2;
// specialization for B
template<>
constexpr std::size_t InternalContainerDefaultSize<B> = 5;
template<class T, std::size_t MaxNumObjects = InternalContainerDefaultSize<T>>
class InternalContainer {
/* ... */
};
InternalContainer<A> aContainer; // size will be 2
InternalContainer<B> bContainer; // size will be 5
InternalContainer<C> cContainer; // size will be 64
// default size can be overriden by explicitly specifying another size
InternalContainer<A, 10> aContainer; // size will be 10
评论
1赞
dkoch
6/27/2023
这基本上是 @Sam Varshavchik 建议的,看起来是最简单干净的解决方案,谢谢!
评论
default_size<T>
InternalContainer
MaxNumObjects
std::array