从嵌套在模板中的类派生时编译问题

时间:2013-10-05 22:26:36

标签: c++ templates c++11 g++ g++4.8

我正在为数独拼图编写模板类,其中模板参数定义行和列的大小。我正在使用g ++ - 4.8并启用了C ++ 11。

我有一个我编写的编译问题,但我想了解为什么它没有按预期工作:

我的RowIteratorImpl类派生自VirtualLineIteratorImpl,但我无法访问其字段virtualLineIdx和cellInVirtualLineIdx,尽管这应该是可能的:

    class VirtualLineIteratorImpl : public CellIteratorImpl
    {
    protected:
        size_t virtualLineIdx;
        size_t cellInVirtualLineIdx;

    public:
        VirtualLineIteratorImpl(size_t virtualLineIdx)
            : virtualLineIdx(virtualLineIdx), cellInVirtualLineIdx(0)
        {}

        virtual void increment(size_t offset)
        {
            virtualLineIdx += offset;
        }
    };

    class RowIteratorImpl : public VirtualLineIteratorImpl
    {
    public:
        using VirtualLineIteratorImpl::VirtualLineIteratorImpl;

        virtual size_t getCellIdx() const 
        {
            // TODO: does not compile
            // return mivTSudoku::getCellIdxInRow(virtualLineIdx, cellInVirtualLineIdx);
            return mivTSudoku::getCellIdxInRow(VirtualLineIteratorImpl::virtualLineIdx, VirtualLineIteratorImpl::cellInVirtualLineIdx);
        }
    };

编译器生成以下消息:

mivSudoku.h:在成员函数'virtual size_t mivTSudoku :: RowIteratorImpl :: getCellIdx()const'中: mivSudoku.h:85:39:错误:未在此范围内声明'virtualLineIdx'     return mivTSudoku :: getCellIdxInRow(virtualLineIdx,cellInVirtualLineIdx);

这是整个班级的定义:

#ifndef MIVSUDOKU_H
#define MIVSUDOKU_H

#include <bitset>
#include <iterator>
#include <memory>

template<size_t n, size_t m=n>
class mivTSudoku
{
public:
    class Cell
    {};

    static constexpr size_t getCellIdx(size_t rowIdx, size_t colIdx) 
    {
        return rowIdx * dim + colIdx;
    }
    static constexpr size_t getCellIdxInRow(size_t rowIdx, size_t cellInRowIdx) 
    {
        return getCellIdx(rowIdx, cellInRowIdx);
    }
    static constexpr size_t getCellIdxInColumn(size_t columnIdx, size_t cellInColumnIdx) 
    {
        return getCellIdx(cellInColumnIdx, columnIdx); 
    }
    static constexpr size_t getCellIdxInBlock(size_t blockIdx, size_t cellInBlockIdx) 
    {
        return getCellIdx((blockIdx / n) * n + (cellInBlockIdx / m), (blockIdx % n) * m + (cellInBlockIdx % m)); 
    }

    class CellIteratorImpl
    {
    public:
        virtual CellIteratorImpl* clone() = 0;
        virtual void increment(size_t) = 0;
        virtual void getCellIdx() const = 0;
    };

    class AllCellIteratorImpl : public CellIteratorImpl
    {
    private:
        size_t m_cellIdx;

    public:
        AllCellIteratorImpl()
            : m_cellIdx(0)
        {}

        virtual void increment(size_t offset)
        {
            m_cellIdx += offset;
        }
        virtual void getCellIdx() const 
        {
            return m_cellIdx;
        }
    };

    class VirtualLineIteratorImpl : public CellIteratorImpl
    {
    protected:
        size_t virtualLineIdx;
        size_t cellInVirtualLineIdx;

    public:
        VirtualLineIteratorImpl(size_t virtualLineIdx)
            : virtualLineIdx(virtualLineIdx), cellInVirtualLineIdx(0)
        {}

        virtual void increment(size_t offset)
        {
            virtualLineIdx += offset;
        }
    };

    class RowIteratorImpl : public VirtualLineIteratorImpl
    {
    public:
        using VirtualLineIteratorImpl::VirtualLineIteratorImpl;

        virtual size_t getCellIdx() const 
        {
            // TODO: does not compile
            //return mivTSudoku::getCellIdxInRow(virtualLineIdx, cellInVirtualLineIdx);
            return mivTSudoku::getCellIdxInRow(VirtualLineIteratorImpl::virtualLineIdx, VirtualLineIteratorImpl::cellInVirtualLineIdx);
        }
    };

    typedef std::bidirectional_iterator_tag CellIterator_tag;
    typedef std::iterator<CellIterator_tag, Cell> CellIteratorBase; 
    class Cellterator : public CellIteratorBase
    {
    private:
        typedef CellIteratorBase baseclass;

    protected:
        mivTSudoku* pSudoku;
        CellIteratorImpl* m_pIterImpl;

    public:
        Cellterator(mivTSudoku* pSudoku, CellIteratorImpl* impl) noexcept
            : pSudoku(pSudoku), m_pIterImpl(impl)
        {
        }

        ~Cellterator()
        {
            delete m_pIterImpl;
            m_pIterImpl = nullptr;
        }

        Cellterator(const Cellterator& rhs) noexcept 
            : pSudoku(pSudoku), m_pIterImpl(rhs.m_pIterImpl->clone())
        {}

        Cellterator(Cellterator&& rhs) noexcept
            : pSudoku(pSudoku), m_pIterImpl(rhs.m_pIterImpl)
        {
            rhs.m_pIterImpl = nullptr;
        }

        Cellterator& operator=(const Cellterator& rhs) noexcept
        {
            if (this == &rhs) return *this;
            this->pSudoku = rhs.pSudoku;
            this->m_pIterImpl = rhs.m_pIterImpl->clone();
        }

        Cellterator& operator=(Cellterator&& rhs) noexcept
        {
            if (this == &rhs) return *this;
            this->pSudoku = rhs.pSudoku;
            this->m_pIterImpl = rhs.m_pIterImpl;
            rhs.m_pIterImpl = 0;
        }

        size_t getCellIdx() const 
        {
            return m_pIterImpl->getCellIdx();
        }

        typedef typename baseclass::reference reference;
        reference operator*()
        {
            return pSudoku->m_field[getCellIdx()];
        }

        reference const operator*() const
        {
            return pSudoku->m_field[getCellIdx()];
        }

        typedef typename baseclass::pointer pointer;
        pointer operator->()
        {
            return pSudoku->m_field + getCellIdx();
        }

        pointer const operator->() const
        {
            return pSudoku->m_field + getCellIdx();
        }

        Cellterator& operator++()
        {
            m_pIterImpl->increment(1);
            return *this;
        }
        Cellterator operator++(int)
        {
            Cellterator iter;
            this->operator++();
            return iter;
        }       
        bool operator==(const Cellterator& rhs) const
        {
            return getCellIdx()==rhs.getCellIdx();
        }
        bool operator!=(const Cellterator& rhs) const
        {
            return !operator==(rhs);
        }
    };

public:
    static const size_t dim = n*m;
    static const size_t ncells = dim*dim;

private:
    Cell m_field[dim];
};


typedef mivTSudoku<3,3> mivSudoku;



#endif // MIVSUDOKU_H

有人能解释一下为什么吗?

1 个答案:

答案 0 :(得分:1)

问题是只有在模板参数未知时才会查找不依赖于模板参数的名称。由于您的基类依赖于模板参数(通过嵌套在模板中隐式),编译器不会查看基类,但是:在模板实例化之前,它可能会被特化,从而产生完全不同的类。

修复是使对基础成员的引用取决于模板参数,例如,使用this->virtualLineIdx