【问题标题】:How to correctly define a partial specialization for a member struct of a templated class?如何正确定义模板类的成员结构的部分特化?
【发布时间】:2018-06-06 14:41:23
【问题描述】:

尝试为模板化成员结构添加 std::iterator_traits 时出现错误 - 即,我有一个迭代器类,它是模板化外部类的成员:

namespace Toolbox {
    template <typename CharType>
    class substring_container_adapter
    {
    public:
        struct iterator // : public std::iterator<std::forward_iterator_tag, const CharType *>   C++ 17 is very upset at this approach!
        {
            // iterator constructor
            iterator(const CharType * pszPosition, const CharType * pszDelimeters)

稍后,我尝试将迭代器特征的部分特化添加到 std,因为显然不推荐从 std::iterator 继承(尽管 - 或 boost::iterator_adaptor 非常有意义并且实际上在这种情况和其他情况下都有效)...

// define iterator traits for our custom iterators
namespace std 
{
    template <typename CharType>
    struct iterator_traits<class Toolbox::substring_container_adapter<CharType>::iterator>
    {
        using iterator_category = forward_iterator_tag;
        using value_type = CharType;
    };
}

但是,VC++ 2017 版本 15.7.3(为此项目启用了 C++ 17)抱怨:

错误 C2764:“CharType”:模板参数未在部分特化“std::iterator_traits::iterator>”中使用或推导出来

为什么不呢?

我怀疑这是 !@#$ 烦人的限制,因为试图部分专门化成员结构而不是 substring_container_adapter 之外的模板化结构?

【问题讨论】:

  • partial specialization 我想你只是错过了将class 关键字添加到struct iterator_traits&lt;class Toolbox:: ...
  • 而且你根本不需要那些部分模板专业化:) 因为ForwardIterator
  • FWIW - 添加更多 typename 说明符不会改变事情(在 VS 2017 中) - 相同的错误结果。似乎基本缺乏语言,它无法处理模板内部类的部分规范构造(但我希望有人可以在这里澄清这一点)
  • @VictorGubin 我不知道这有什么帮助(目前)——因为概念仍然不是语言的一部分。
  • 请注意,您需要所有 5 个别名都是正确的 std::iterator_traits,因此您不会在那里获得任何东西。

标签: visual-studio templates c++17 partial-specialization


【解决方案1】:

这里正确的做法是将类型别名放入iterator,而不是尝试部分特化std::iterator_traits

namespace Toolbox {
    template <typename CharType>
    class substring_container_adapter
    {
    public:
        struct iterator // : public std::iterator<std::forward_iterator_tag, const CharType *>   C++ 17 is very upset at this approach!
        {
            using iterator_category = forward_iterator_tag;
            using value_type = const CharType *;
            using reference = const CharType * &;
            using pointer = const CharType * *;
            using difference_type = std::ptrdiff_t;

            // iterator constructor
            iterator(value_type pszPosition, value_type pszDelimeters)

            // ...
        }
    }
}

弃用std::iterator 的一个主要原因是委员会不喜欢它给人的印象,即所有Iterators 都应该从它派生,因为不需要任何容器迭代器。你可以定义一个精确的替换

namespace not_std {
  template<class Category, class T, class Distance = ptrdiff_t,
           class Pointer = T*, class Reference = T&>
  struct iterator {
    using iterator_category = Category;
    using value_type        = T;
    using difference_type   = Distance;
    using pointer           = Pointer;
    using reference         = Reference;
  };
}

【讨论】:

  • 这看起来完全合理。但是为什么这是首选(除了“它有效!”;)我真的想声明我的迭代器类是一种迭代器,而不是必须零碎地指定事物(只是感觉错误或任意)
  • 顺便说一句,如果我从boost::iterator_adaptor&lt;&gt; 继承,我实际上得到了上面的内容
  • 谢谢。这是他们的推理——我个人认为这有点糟糕。就像我之前的评论一样——这只是一组随意的 using 声明,没有押韵也没有理由(除了在细节中我们都必须代表 c++ 和标准机构的特质隐藏起来 - 废话!)不鄙视你 - 我很感激清楚地知道“为什么”-但我会郑重声明“这很愚蠢”(纯粹是 IMO)。 ;)
  • 这是一个完美的解决方法。我可能会将其标记为答案。但我希望有人能澄清 c++17 中存在哪些限制,这使得无法对模板的内部类型进行 std::iterator_traits 的部分特化。
猜你喜欢
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
相关资源
最近更新 更多