我正在为数独拼图编写模板类,其中模板参数定义行和列的大小。我正在使用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
有人能解释一下为什么吗?
答案 0 :(得分:1)
问题是只有在模板参数未知时才会查找不依赖于模板参数的名称。由于您的基类依赖于模板参数(通过嵌套在模板中隐式),编译器不会查看基类,但是:在模板实例化之前,它可能会被特化,从而产生完全不同的类。
修复是使对基础成员的引用取决于模板参数,例如,使用this->virtualLineIdx
。