【问题标题】:Using templates to specify member variable使用模板指定成员变量
【发布时间】:2020-06-15 19:45:10
【问题描述】:

这里我有一个带有类模板的二叉搜索树类:

template <class T>
class Tree {
    T* root_ptr;
public:
    void Insert(T* ptr_to_value);
};

template <typename T>
void Tree<T>::Insert(T* ptr_to_value) {
    T** temp = &root_ptr;
    while (*temp) {
        if (ptr_to_value->name <= (*temp)->name)
            temp = &(*temp)->left_ptr;
        else
            temp = &(*temp)->right_ptr;
    }
    (*temp) = ptr_to_value;
}

但它指的是T 类的name 变量,我可能希望与其他成员变量进行比较。我想要template &lt;/*some type*/ data&gt; 之类的东西,这样我就可以初始化Tree&lt;Node, name&gt;Tree&lt;Node, Node.name&gt; 之类的树。

【问题讨论】:

  • with other member variable 什么?你能给我们举个例子吗?如果Node 始终存在,只需将其用作您的Tree&lt;T&gt; 成员类型Node&lt;T&gt; root_ptr

标签: c++ class templates


【解决方案1】:

模板参数不必是类型;它们也可以是某些非类型,只要它们是编译常量。指向成员的指针符合条件!

template <class T, auto Ptr>
class Tree {
    T* root_ptr;
public:
    void Insert(T* ptr_to_value);
};

template <typename T>
void Tree<T>::Insert(T* ptr_to_value)
{
    T** temp = &root_ptr;
    while (*temp) {
        if (ptr_to_value->*Ptr <= (*temp)->*Ptr)
            temp = &(*temp)->left_ptr;
        else
            temp = &(*temp)->right_ptr;
    }
    (*temp) = ptr_to_value;
}

// Tree<Foo, &Foo::name> t;
// t.insert(&val);

?


如果你不能使用auto模板参数,因为你的C++太老了,你需要把它拼出来:

template <class T, class T2, T2 Tree<T>::*Ptr>
class Tree {

然后:

// Tree<Foo, std::string, &Foo::name> t;
// t.insert(&val);

但请注意,Visual Studio 16.6.1 存在将指向成员的指针作为模板参数传递的错误,目前仅接受 auto Ptr 变体。

另外,想想看,这个变体可能无法正常工作,因为我在知道之前拼写为 Tree&lt;T&gt;


比较器 作为模板参数传递更为传统,因此有人可以定义整个 &lt;= 位,而不是仅限于命名单个数据成员。我建议你看看标准的mapset 是如何工作的。

【讨论】:

  • 这样我初始化它就像Tree&lt;Node, &amp;Node.name&gt;?
  • @AlexeiSavitsky 我提供了示例用法。
  • 如果将函数中的Ptr替换为&amp;T::Ptr,这样我就可以像Tree&lt;Node, name&gt;一样初始化它,并且禁止使用除T的成员变量之外的任何变量。
  • @AlexeiSavitsky 不,你不能那样做。 name 不是独立存在的。
【解决方案2】:

您可以让Tree 保存比较函数,而不是直接在您的Insert 方法中进行比较。这是标准容器采用的方法。

例如:

template <typename T, typename Comp = std::less<T>>
class Tree {
    T* root_ptr;
    Comp comp;
public:
    Tree(Comp comp = Comp{})
      : root_ptr{nullptr},
        comp{comp}
    {
    }
    void Insert(T* ptr_to_value);
};

template <typename T, typename Comp>
void Tree<T, Comp>::Insert(T* ptr_to_value) {
    T** temp = &root_ptr;
    while (*temp) {
        if (comp(*ptr_to_value, **temp))
            temp = &(*temp)->left_ptr;
        else
            temp = &(*temp)->right_ptr;
    }
    (*temp) = ptr_to_value;
}

struct Foo {
    int foo;
    Foo* left_ptr;
    Foo* right_ptr;
};

bool operator<(const Foo& left, const Foo& right) {
    return left.foo < right.foo;
}

struct CompareFoosGreater {
    bool operator()(const Foo& left, const Foo& right) {
        return left.foo > right.foo;
    }
};

int main() {
    // Defaults to using std::less, which compares
    // objects using the < operator
    Tree<Foo> foo_tree_less;
    // Use a custom comparator
    Tree<Foo, CompareFoosGreater> foo_tree_greater;
}

与使用指向成员的指针相比,这有几个优点:

  1. 您可以比较多个属性
  2. 您可以更改存储元素的顺序
  3. 功能可以完全以您的类型编码

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-26
    • 2015-09-15
    • 2017-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    相关资源
    最近更新 更多