从嵌套在模板中的类派生时编译问题
Compiling issues when deriving from a class nested in a template
我正在为数独谜题编写模板类,其中模板参数定义了行和列的大小。我正在使用启用了 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
.
相关文章:
- 使用 std::enable_if 限制派生类的模板参数时出现编译错误
- 基于派生类型的编译时行为分支
- C++:编译对无关派生类、bug或特性的函数调用
- 如果所有派生类在编译时都是已知的,那么final关键字是否提供了优化
- 如何创建指向派生类的新指针,该派生类在C++编译时未知
- 从std::map派生的类不在Visual C++上编译(但在gcc和clang上编译)
- 在编译时间定义多个派生类
- 如果未实现虚函数,则大多数派生类无法编译,但如果一个基类未实现虚函数,则可以编译
- 为什么这两个涉及受保护派生类的C++示例的编译方式不同?
- 在向量中使用派生的可移动但不可压缩的会导致编译错误
- 选择要在编译时使用的派生类
- 通过迭代器调用功能无法在派生对象上编译
- OpenCV模板化代码在派生类中产生编译错误
- 在Linux上的命令行上编译QObject派生类
- 将模板方法移动到派生中断编译
- 重新编译二进制类或派生类,以便在基类中添加新方法
- 在派生类中缺少静态成员变量时强制编译错误
- 将派生对象声明为类中的私有成员时发生编译错误
- 无法使派生的 WebDuino 类工作 - 使用 'Web_HelloWorld.ino' 编译错误
- 从嵌套在模板中的类派生时编译问题