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

Compiling issues when deriving from a class nested in a template

本文关键字:派生 编译 问题 嵌套      更新时间:2023-10-16

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

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

我的 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: In member function '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

有人可以向我解释为什么吗?

问题是,

仅当模板参数未知时,才会查找不依赖于模板参数的名称。由于基类依赖于模板参数(隐式嵌套在模板中),因此编译器不会查看基类:在模板实例化之前,它可能会被专用化,从而产生完全不同的类。

解决方法是使对基成员的引用依赖于模板参数,例如,通过使用 this->virtualLineIdx .