c++ 如何根据类型更改/设置模板参数?

mrwjdhj3  于 2023-07-01  发布在  其他
关注(0)|答案(2)|浏览(127)

我想创建一个静态类,它将充当固定大小的内存分配器。
让我们看看这个简单的例子:

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>;
gojuced7

gojuced71#

这可以通过显式地专门化变量模板来轻松实现,例如:
godbolt example

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
f0ofjuux

f0ofjuux2#

如何根据类型预定义容器的最大大小?
你有几个选择。最简单的方法是为默认类型提供专门化(即AB

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>>);

See live demo in godbolt.org
或者,使用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>

See live demo in godbolt.org
或者,使用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>
>;

See live demo in godbolt.org

相关问题