Проблемы компиляции при наследовании от класса, вложенного в шаблон [duplicate]

0

Я пишу шаблон класса для головоломки судоку, где параметры шаблона определяют размер строк и столбцов. Я использую g++ - 4.8 с включенным С++ 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

Может кто-нибудь объяснить мне, почему?

Теги:
c++11
templates
g++
g++4.8

1 ответ

1
Лучший ответ

Проблема в том, что имена, не зависящие от аргумента шаблона, просматриваются только тогда, когда аргументы шаблона неизвестны. Поскольку ваш базовый класс зависит от аргумента шаблона (неявно, будучи вложенным внутри шаблона), компилятор не смотрит на базовый класс, но: пока экземпляр шаблона не будет создан, он может получить specialuzed, что приведет к совершенно другому классу.

Исправление состоит в том, чтобы ссылка на базовый элемент зависела от аргумента шаблона, например, с помощью this->virtualLineIdx.

  • 0
    Спасибо. Если вы хотите получить более подробный ответ, взгляните на ссылку, предоставленную nosid.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню