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

How to change/set template parameter based on type?

提问人:dkoch 提问时间:6/26/2023 最后编辑:JeJodkoch 更新时间:6/27/2023 访问量:160

问:

我想创建一个静态类,它将充当固定大小的内存分配器。

让我们看一下这个简化的例子:

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>;
C++ C++17 专业化 类-模板

评论

3赞 Sam Varshavchik 6/26/2023
您是否尝试过定义一个简单的模板,例如解析为 2 或 5?这可以通过教科书专业化来完成。然后,只需在 .任务完成。default_size<T>InternalContainer
1赞 Some programmer dude 6/26/2023
某种专业化怎么样?也许与CRTP继承的通用基类一起?
1赞 Paul Sanders 6/27/2023
我不确定这是否使工作更容易,但为什么会有模板参数呢?为什么不让它成为构造函数的参数呢?MaxNumObjects
0赞 Some programmer dude 6/27/2023
为了扩展@PaulSanders的评论,您需要解决的实际潜在真正的问题是什么?为什么需要“容器”?为什么需要自己做?为什么不能使用?现在,这真的是一个太多的XY问题。如果你问的是实际的、潜在的和真正的问题(你的任务),那么也许还有其他解决方案,甚至可能更好、更简单?std::array

答:

8赞 JeJo 6/26/2023 #1

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

您在这里有几个选择。 最简单的方法是为默认类型(即 ,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>>);

观看现场演示 godbolt.org


或者,使用 if constexpr(需要 c+ 或更高版本),您可以执行如下操作:

#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>

观看现场演示 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>
>;

观看现场演示 godbolt.org

评论

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
问题在于您的实现依赖于 和 。因此,如果此代码的用户想要为其他未知类自定义项目数,他必须修改您的代码以添加 .这违反了开盘原则。在其他答案中,您可以提供专业化,而不必触摸实现细节。ABXifX
6赞 Turtlefight 6/27/2023 #2

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

Godbolt 示例

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 建议的,看起来是最简单干净的解决方案,谢谢!