dko*_*och 2 c++ templates template-specialization class-template c++17
我想创建一个静态类,它将充当固定大小的内存分配器。
让我们看一下这个简化的例子:
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();
Run Code Online (Sandbox Code Playgroud)
如何根据类型预定义容器的最大尺寸?
// will be replaced "InternalContainer<A, 2>"
A* a = MyContainer<A>::createObject();
// will be replaced "InternalContainer<B, 5>"
B* b = MyContainer<B>::createObject();
Run Code Online (Sandbox Code Playgroud)
我尝试过类似的方法,但它不起作用:
template<class T>
using MyContainer = InternalContainer<A, 2>;
template<class T>
using MyContainer = InternalContainer<B, 5>;
Run Code Online (Sandbox Code Playgroud)
如何根据类型预定义容器的最大尺寸?
您在这里有多种选择。最简单的方法是为默认类型提供专门化(即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>>);
Run Code Online (Sandbox Code Playgroud)
或者,使用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>
Run Code Online (Sandbox Code Playgroud)
或者,使用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>
>;
Run Code Online (Sandbox Code Playgroud)
这可以通过显式专门化变量模板来轻松完成,例如:
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
Run Code Online (Sandbox Code Playgroud)