我正在编写一个包含容器类的类IteratorIterable
(一个具有begin()
和end()
方法的类返回一些迭代器),以便可以迭代包装类的迭代器。这个想法基于this post。我的代码看起来像这样(为简洁起见,遗漏了一些方法):
template <class T>
class IteratorIterable
{
private:
T& container;
public:
typedef decltype(container.begin()) BackendIterator;
public:
class IteratorIterator
{
public:
IteratorIterator() : it() {}
IteratorIterator(BackendIterator it) : it(it) {}
IteratorIterator(const IteratorIterator& other) : it(other.it) {}
IteratorIterator& operator=(const IteratorIterator& other) { if (&other == this) return *this; it = other.it; return *this; }
BackendIterator operator*() const { return it; }
const BackendIterator* operator->() const { return ⁢ }
bool operator==(const IteratorIterator& other) { return it == other.it; }
bool operator !=(const IteratorIterator& other) { return it != other.it; }
IteratorIterator operator+(size_t n) { return IteratorIterator(it + n); }
IteratorIterator& operator++() { ++it; return *this; }
IteratorIterator operator++(int) { IteratorIterator cpy(*this); ++(*this); return cpy; }
private:
BackendIterator it;
};
public:
IteratorIterable(T& container) : container(container) {}
IteratorIterator begin() const { return IteratorIterator(container.begin()); }
IteratorIterator end() const { return IteratorIterator(container.end()); }
};
template <class T>
IteratorIterable<T> ItIt(T& container)
{
return IteratorIterable<T>(container);
}
问题在于,operator+()
中的IteratorIterator
方法仅对随机访问BackendIterator
有效,因为否则后端未定义加法运算符。我希望我的IteratorIterator仅在后端支持时提供此方法。
考虑这个示例代码:
typedef list<int> Cont;
Cont vec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
IteratorIterable<Cont> itb(vec);
IteratorIterable<Cont>::IteratorIterator beg = itb.begin();
IteratorIterable<Cont>::IteratorIterator it = beg;
it++;
//it = beg+1;
printf("%d\n", **it);
这在使用it++
行时编译得很好,但是 - 正如预期的那样 - 在it = beg+1
行失败,因为list<int>::iterator
不是随机访问。我想这是因为如果我实际上实例化 IteratorIterator::operator+()
,编译器就不在乎了。
我知道模板只允许对某些模板参数有效,但这里的类是模板化的,而不是方法。当该方法从未用于此特定实例化时,实例化其中一个方法无效的类模板是否正确? GCC和Clang不抱怨,但按照C ++标准是否正确?
答案 0 :(得分:4)
是的,该标准保证类模板的隐式实例化仅导致声明的隐式实例化,而不是成员函数的定义。
§14.7.1[temp.inst]
1
...
类模板特化的隐式实例化导致隐式 声明的实例化,但不是定义,默认参数或类成员函数的异常规范,成员类,作用域成员枚举,静态数据成员和成员模板;它会导致隐式实例化未作用域成员枚举和成员匿名联合的定义。11 实现不得隐式实例化功能模板,变量模板,成员模板,非虚拟成员函数,成员类,或不需要实例化的类模板的静态数据成员。
...
请注意,如果您显式实例化类
,您的代码将无法编译是否使用operator+
template class IteratorIterable<std::list<int>>;
除非enable_if
是随机访问迭代器,否则可以通过BackendIterator
向SFINAE使用过载集中的成员函数来防止这种情况发生。
template<typename Iter = BackendIterator>
typename std::enable_if<
std::is_same<typename std::iterator_traits<Iter>::iterator_category,
std::random_access_iterator_tag>::value,
IteratorIterator>::type
operator+(size_t n)
{
return IteratorIterator(it + n);
}
答案 1 :(得分:1)