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

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

<分区>

我正在为数独游戏编写模板类,其中模板参数定义行和列的大小。我正在使用启用了 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:在成员函数‘virtual size_t mivTSudoku::RowIteratorImpl::getCellIdx() const’中: mivSudoku.h:85:39: 错误:未在此范围内声明“virtualLineIdx” 返回 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

关于c++ - 从嵌套在模板中的类派生时的编译问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19203367/

相关文章:

c++函数重载问题

c++ - 如何在 VS 2017 中为 C++ 添加单元测试?

templates - Golang 从文件中嵌入 html

c++ - 如何用继承或模板(或其他任何东西?)

c++ - 通过用户定义的转换复制类类型的初始化

C++ 使用迭代器复制文本文件

c++ - 用于在稀疏域中设置位和迭代(C++)的快速容器?

c++ - 特殊类的虚方法

c++ - 错误 : binding ‘const double’ to reference of type ‘double&’ discards qualifiers

c++ - static, constexpr, const - 它们一起使用时是什么意思?