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

huangapple go评论73阅读模式
英文:

How to change/set template parameter based on type?

问题

I want to create a static class, which will act as a fixed-size memory allocator.

让我们看一个简化的示例:

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

如何根据类型预定义容器的最大大小?

// 将被替换为 "InternalContainer<A, 2>"
A* a = MyContainer<A>::createObject(); 

// 将被替换为 "InternalContainer<B, 5>"
B* b = MyContainer<B>::createObject();

我尝试了类似以下的方法,但它不起作用:

template<class T>
using MyContainer = InternalContainer<A, 2>;
template<class T>
using MyContainer = InternalContainer<B, 5>;
英文:

I want to create a static class, which will act as fixed size memory allocator.

Lets look at this simplified example:

struct A {};
struct B {};

template&lt;class T, std::size_t MaxNumObjects&gt;
class InternalContainer
{
public:
    static constexpr std::size_t maxObjects = MaxNumObjects;

    static T* createObject()
    {
        return ::new(&amp;objects[idx++]) T;
    }
    static T* releaseObject() { /*...*/ };

private:
    using buffer_t = std::aligned_storage_t&lt;sizeof(T), alignof(T)&gt;;
    static buffer_t objects[maxObjects];
    static std::size_t idx;
};

A* a = InternalContainer&lt;A, 2&gt;::createObject();
B* b = InternalContainer&lt;B, 5&gt;::createObject();

How can I predefine the maximum size of the container based on type?

// will be replaced &quot;InternalContainer&lt;A, 2&gt;&quot;
A* a = MyContainer&lt;A&gt;::createObject(); 

// will be replaced &quot;InternalContainer&lt;B, 5&gt;&quot;
B* b = MyContainer&lt;B&gt;::createObject();

I have tried something like this, but it does not work:

template&lt;class T&gt;
using MyContainer = InternalContainer&lt;A, 2&gt;;
template&lt;class T&gt;
using MyContainer = InternalContainer&lt;B, 5&gt;;

答案1

得分: 8

Sure, here's the translated code portion:

&gt; 如何根据类型预定义容器的最大大小?

您有几个选项。
最简单的方法是为默认类型(即`A`、`B`)提供专门化。

template <class T> struct MyContainer;
// 为 A 进行专门化
template <> struct MyContainer<A> {
using type = InternalContainer<A, 2>;
};
// 为 B 进行专门化
template <> struct MyContainer<B> {
using type = InternalContainer<B, 5>;
};
// ...以此类推!

// 辅助别名
template <class T>
using MyContainer_t = typename MyContainer<T>::type;

static_assert(std::is_same_v<MyContainer_t<A>, InternalContainer<A, 2>>);


[在godbolt.org中查看在线演示](https://gcc.godbolt.org/z/6n51jcKhM)

----------

另外,您还可以使用 [`if constexpr`][1](需要 [tag:C++17] 或更高版本)来尝试以下操作:

#include <type_traits>

template <class T>
constexpr auto typeHelper()
{
// 以下需要 InternalContainer<T, N> 可以默认构造!
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(); // 将被替换为 InternalContainer<A, 2>
B* b = MyContainer<B>::createObject(); // 将被替换为 InternalContainer<B, 5>


[在godbolt.org中查看在线演示](https://gcc.godbolt.org/z/vPj9ccTvf)

----------

此外,您还可以使用 [`std::conditional_t`][2],如下所示:

#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>,
/如果类型既不是A也不是B,则默认情况/ void>
>;


[在godbolt.org中查看在线演示](https://gcc.godbolt.org/z/oKW6GKj7K)

  [1]: https://en.cppreference.com/w/cpp/language/if
  [2]: https://en.cppreference.com/w/cpp/types/conditional
英文:

> How can I predefine the maximum size of the container based on type?

You have several options here.
The easiest, would be providing a specialization for the default types (i.e. A, B )

template &lt;class T&gt; struct MyContainer;
// specialization for A
template &lt;&gt; struct MyContainer&lt;A&gt; {
    using type = InternalContainer&lt;A, 2&gt;;
};
// specialization for B
template &lt;&gt; struct MyContainer&lt;B&gt; {
    using type = InternalContainer&lt;B, 5&gt;;
};
// ... so on!

// Helper alias
template &lt;class T&gt;
using MyContainer_t = typename MyContainer&lt;T&gt;::type;

static_assert(std::is_same_v&lt;MyContainer_t&lt;A&gt;, InternalContainer&lt;A, 2&gt;&gt;);

See live demo in godbolt.org


Alternatively, using if constexpr (requires [tag:C++17] or higher) you might be able to do something like as follows:

#include &lt;type_traits&gt;

template &lt;class T&gt;
constexpr auto typeHelper()
{
    // following requires the InternalContainer&lt;T, N&gt; be default constructible!!
    if constexpr (std::is_same_v&lt;T, A&gt;) return InternalContainer&lt;A, 2&gt;{};
    else if constexpr (std::is_same_v&lt;T, B&gt;) return InternalContainer&lt;B, 5&gt;{};
}

template &lt;class T&gt;
using MyContainer = decltype(typeHelper&lt;T&gt;());

A* a = MyContainer&lt;A&gt;::createObject(); // will be replaced b InternalContainer&lt;A, 2&gt;
B* b = MyContainer&lt;B&gt;::createObject(); // will be replaced b InternalContainer&lt;B, 5&gt;

See live demo in godbolt.org


Alternatively, using std::conditional_t you could do also

#include &lt;type_traits&gt; //  std::conditional_t

template &lt;class T&gt;
using MyContainer = std::conditional_t&lt;std::is_same_v&lt;T, A&gt;, InternalContainer&lt;A, 2&gt;,
    std::conditional_t&lt;std::is_same_v&lt;T, B&gt;, InternalContainer&lt;B, 5&gt;,
    /*Default case if types are not A nor B*/ void&gt;
&gt;;

See live demo in godbolt.org

答案2

得分: 6

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

struct A {};
struct B {};
struct C {};

// 所有 InternalContainers 的默认大小
template<class T>
constexpr std::size_t InternalContainerDefaultSize = 64;
// 专门为 A 的情况
template<>
constexpr std::size_t InternalContainerDefaultSize<A> = 2;
// 专门为 B 的情况
template<>
constexpr std::size_t InternalContainerDefaultSize<B> = 5;

template<class T, std::size_t MaxNumObjects = InternalContainerDefaultSize<T>>
class InternalContainer {
    /* ... */
};

InternalContainer<A> aContainer; // 大小将为 2
InternalContainer<B> bContainer; // 大小将为 5
InternalContainer<C> cContainer; // 大小将为 64

// 默认大小可以通过显式指定另一个大小来覆盖
InternalContainer<A, 10> aContainer; // 大小将为 10

godbolt 示例

英文:

This can be easily accomplished by explicitly specializing a variable template, e.g.:

godbolt example

struct A {};
struct B {};
struct C {};

// default size for all InternalContainers
template&lt;class T&gt;
constexpr std::size_t InternalContainerDefaultSize = 64;
// specialization for A
template&lt;&gt;
constexpr std::size_t InternalContainerDefaultSize&lt;A&gt; = 2;
// specialization for B
template&lt;&gt;
constexpr std::size_t InternalContainerDefaultSize&lt;B&gt; = 5;

template&lt;class T, std::size_t MaxNumObjects = InternalContainerDefaultSize&lt;T&gt;&gt;
class InternalContainer {
    /* ... */
};


InternalContainer&lt;A&gt; aContainer; // size will be 2
InternalContainer&lt;B&gt; bContainer; // size will be 5
InternalContainer&lt;C&gt; cContainer; // size will be 64

// default size can be overriden by explicitly specifying another size
InternalContainer&lt;A, 10&gt; aContainer; // size will be 10

huangapple
  • 本文由 发表于 2023年6月26日 23:44:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76558246.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定