C++使用指针的类模板专用化

C++ class template specialization with pointers

本文关键字:专用 指针 C++      更新时间:2023-10-16

我有一个以下格式的树结构:

template <typename DataType>
class Tree {
    DataType *accessData() { return data; } 
    Tree *child1, *child2;
    DataType *data;
};
template <typename DataType>
class Root : public Tree<DataType> {
    // root provides storage of nodes; when it goes out of scope, the
    // entire tree becomes invalid
    MemoryPool<Tree> nodeStorage;
    MemoryPool<DataType> dataStorage; 
};

我在程序中使用此模板的各种实例化。效果很好。

然而,一个实例化使用了一个只是一个枚举的DataType(所以它与指针的大小相同!),并且因为速度是必不可少的(无论是在构建树时还是在访问树时),我宁愿让这个实例化直接使用枚举而不是指针。我希望代码的外观示例(不严格):

Tree<BigClass> *foo = ...;
foo->accessData()->doBigClassThings();
Tree<int> *bar = ...;
int x = 4 + bar->accessInt();

现在当然我可以保留当前的模板,但我不喜欢这种额外的指针访问,尤其是需要在根目录中分配整数。关于如何使模板专用化以提供此功能或其他方法的任何想法?

我试图像这样专门化模板(以及其他无数种方式)

template <> Tree<int> { ... }

但我只是不断收到编译错误。任何帮助将不胜感激!

我建议使用traits类来推断存储在Tree中的对象的类型。

// The default traits.
template <typename DataType> struct TreeDataType
{
   using Type = DataType*;
};
template <typename DataType>
class Tree {
   // Define the data type using the traits class.
   using Data = typename TreeDataType<DataType>::Type;
   Data accessData() { return data; } 
   Tree *child1, *child2;
   Data data;
};

然后专门TreeDataType MyEnum.

template <> struct TreeDataType<MyEnum>
{
   using Type = MyEnum;
};

我建议使用同一接口定义多个data类,您可以将其用作DataType模板参数。将数据的存储方式与访问数据的方式抽象出来。

template<typename T>
class value_data
{
private:
    T _value;
public:
    T& access() { return _value; }
    const T& access() const { return _value; }
};
template<typename T>
class unique_ptr_data
{
private:
    std::unique_ptr<T> _value;
public:
    T& access() { assert(_value != nullptr); return *_value; }
    const T& access() const { assert(_value != nullptr); return *_value; }
};
enum class my_enum { /* ... */ };
class my_enum_data
{
private:
    my_enum _value;
public:
    my_enum& access() { return _value; }
    const my_enum& access() const { return _value; }
};

然后,在Tree类中,您可以通过它们的通用接口使用它们:

template <typename DataType>
class Tree {
    auto& accessData() { return data.access(); } 
    Tree *child1, *child2;
    DataType data;
};