【问题标题】:Inner class of template class will not compile on XCode 4.5.2模板类的内部类不会在 XCode 4.5.2 上编译
【发布时间】:2013-02-27 00:33:39
【问题描述】:

在 XCode 4.5.2 中,下面定义的类 Proxy 无法编译。如有必要,我可以提供有关特定编译器的更多详细信息,尽管它应该是默认值,因为我没有更改 XCode 配置中的任何内容。它在 VStudio Express 中编译。

#include <list>
#include <boost/thread/tss.hpp>

template <typename T>
class Cache
{
public:
    class Proxy : public T
    {
        friend class Cache;

    private:
        std::list<Proxy> & m_refList;
        typename std::list<Proxy>::iterator m_clsPosition;

        Proxy(std::list<Proxy> & refList) : m_refList(refList) {}
    };

private:
    std::list<Proxy> m_clsList;
    typename std::list<Proxy>::iterator m_clsCurrent;

    static void Release(Proxy * ptrProxy)
    {
        ptrProxy->m_refList.splice(ptrProxy->m_refList.m_clsCurrent,
                                   ptrProxy->m_refList,
                                   ptrProxy->m_clsPosition);
        if ( ptrProxy->m_refList.m_clsCurrent == ptrProxy->m_refList.end() )
            --(ptrProxy->m_refList.m_clsCurrent);
    }

public:
    Cache() {m_clsCurrent = m_clsList.end();}
    ~Cache()
    {
        if ( m_clsList.size() && m_clsCurrent != m_clsList.begin() )
        {
            // ERROR - Cache not empty
        }
    }

    typedef boost::shared_ptr<Proxy> Ptr;

    static Ptr Get()
    {
        static boost::thread_specific_ptr<Cache> clsCache;
        if ( clsCache.get() == NULL )
            clsCache.reset(new Cache());

        Proxy * ptrProxy;
        if ( clsCache->m_clsCurrent == clsCache->m_clsList.end() )
        {
            clsCache->m_clsList.push_front(Proxy(clsCache->m_clsList));
            ptrProxy = &(clsCache->m_clsList.front());
            ptrProxy->m_clsPosition = clsCache->m_clsList.begin();
        }
        else
        {
            ptrProxy = &(*(clsCache->m_clsCurrent));
            ptrProxy->m_clsPosition = clsCache->m_clsCurrent++;
        }
        return Ptr(ptrProxy, Release);
    }
};

编译错误就在typename std::list&lt;Proxy&gt;::iterator m_clsPosition这一行:

No type named 'iterator' in 'std::__1::list<ASW::Cache<std::__1::basic_string<char>>::Proxy, std::__1::allocator<ASW::Cache<std::__1::basic_string<char>>::Proxy>>'

(Cache的模板参数为std::basic_string&lt;char&gt;

我了解发生了什么 - 我在完全定义之前引用了 Proxy。但是为什么iterator需要Proxy的定义才能编译呢?

数据结构的原因有两个:1)回收对象而不是销毁它们,2)通过将缓存对象中的迭代器保持在列表中的位置来加速回收。如果有人对如何实现这些有更好的想法(假设无法修复此错误),我很想听听。

【问题讨论】:

  • 从其他 cmets 可以看出,这是由于标准的限制。我简要地研究了boost::container::list,这本来是可行的,因为它被设计为包含不完整的类型;我还查看了boost::ptr_list,但运行时不是 O(1) 用于移动列表中的节点。我最终滚动了自己的,我讨厌为这样的常见任务做这件事。测试完代码我会贴出来的。

标签: c++ xcode templates stl iterator


【解决方案1】:

您的代码具有未定义的行为,因为您正在用不完整的类型实例化 std::listProxy 尚未在其定义中定义)。 [res.on.functions]/2:

...效果未定义...如果在实例化模板组件时将不完整的类型用作模板参数,除非该组件特别允许。

尝试使用listworks with incomplete types 的实现,例如boost::container::list

【讨论】:

  • 我担心是这样的。我没有实例化std::list&lt;Proxy&gt;,而是std::list&lt;Proxy&gt;::iterator。为什么编译器必须能够编译所有std::list&lt;Proxy&gt;才能编译std::list&lt;Proxy&gt;::iterator,既然如此,为什么标准需要这样的东西?我不介意使用 boost 库,我只是更喜欢最简单、最常见的类作为首选。
  • @jorgander:使用std::list&lt;Proxy&gt;::iterator 意味着std::list&lt;Proxy&gt; 的实例化(否则iterator typedef 将在哪里定义?)。据我所知,标准没有充分的理由给出这种未定义的行为(除了委员会缺乏时间和/或缺乏相关提案)。
  • 我确信标准委员会有他们的理由,但我不明白内部类实例化如何需要外部类实例化。编译器可以在传递任何模板参数之前(例如,当第一次在源代码中解析时)知道模板的结构,并且只编译/实例化必要的内容。一般来说,MS 绕过标准是错误的,但我认为他们对此做出了正确的决定。无论如何,它就是这样。感谢您证实我的怀疑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-06
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
相关资源
最近更新 更多