【问题标题】:Determine type of template parameter in template确定模板中模板参数的类型
【发布时间】:2020-12-04 18:01:59
【问题描述】:

我正在尝试在 C++ 中实现一个通用链表和链表迭代器。我有一个节点结构如下

template <typename T>
struct Node
{
    T m_data;
    Node<T>* m_next;
};

我还有一个链表迭代器,它是一个模板,因此它可以生成常规迭代器和const 迭代器。

template <typename NodeType>
class LinkedListIterator
{  
private:
    NodeType* m_node;
public:
    LinkedListIterator(NodeType* n);
    T& operator*() const;
};

我的问题是如何正确声明operator*() 函数?我的期望是像下面这样的东西应该可以工作

LinkedListIterator<const Node<T>> my_iter(some_node_pointer);
*my_iter = new_value; // should not work

我知道在 operator*() 中返回 T 没有意义,因为此类无权访问 Node 类中的类型名。

我找到了一种解决方法,方法是为 Node 类中的类型创建别名,就像这样

template <typename T>
struct Node
{
    typedef T type_value;
    // rest of Node class...
};

现在我可以在我的迭代器类中执行以下操作

template <typename NodeType>
class LinkedListIterator
{
public:
    typename NodeType::type_value& operator*() const;
};

这似乎有效并且会返回正确的值。所以我的问题真的应该是,这是实现这一点的最佳方式吗?我需要typedef 来创建别名以便我可以使用该类型吗?或者有没有办法确定LinkedListIterator 类中的类型?

【问题讨论】:

  • typedef(或更好的 C++11 及更高版本中的 using)是处理此问题的一种方法,是的。另一种方法是只使用auto,例如:auto&amp; operator*() const { return m_node-&gt;m_data; }
  • “内部类型的别名”是 C++ 库本身一直在做的事情。您会惊讶地发现每个 C++ 容器的 value_type 成员,以及它的实际来源。你猜对了。别名。
  • 虽然不相关,但我发现boost::typeindex::type_id_with_cvr&lt;decltype(arg) or T&gt;().pretty_name(); 有助于查看 T 和参数的类型。

标签: c++ templates iterator typename


【解决方案1】:

像这样使用typedef 是规范的做法,并且经常在标准库中完成。实际上,所有LegacyIterators 都应该定义value_typedifference_typereferencepointeriterator_category。只有这样才能使用std::iterator_traits 普遍访问它们的特征。

例如:

// a simple forward iterator
struct Iterator {
    using value_type = int;
    using reference = value_type &;
    using pointer = value_type *;
    using difference_type = std::ptrdiff_t;
    using iterator_category = std::forward_iterator_tag;

    // LegacyIterators also need two operators to be defined:

    // the result of operator* is unspecified, we can choose it freely
    value_type operator*();
    // operator++ needs to return a reference to self
    Iterator& operator++();
};

// we can now access the traits universally, as can various standard library functions
static_assert (std::is_same_v<std::iterator_traits<Iterator>::value_type, int> );

总之,您正在做的是正确的方法,但您应该坚持使用这些确切的名称,以便标准库可以访问您的迭代器的特征。另外我建议使用using 而不是typedef。它不仅将= 用作视觉分隔符,而且普遍适用,例如与typedef 不同,它可以被模板化。见What is the difference between 'typedef' and 'using' in C++11?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多