这可以做到,但需要几个步骤才能干净地完成。首先,编写一个template class
表示一系列连续值的 a。然后将template
知道有多大的版本转发到采用此连续范围array
的版本。Impl
最后,实现contig_range
版本。请注意,它for( int& x: range )
适用于contig_range
,因为我实现了begin()
andend()
和 指针是迭代器。
template<typename T>
struct contig_range {
T* _begin, _end;
contig_range( T* b, T* e ):_begin(b), _end(e) {}
T const* begin() const { return _begin; }
T const* end() const { return _end; }
T* begin() { return _begin; }
T* end() { return _end; }
contig_range( contig_range const& ) = default;
contig_range( contig_range && ) = default;
contig_range():_begin(nullptr), _end(nullptr) {}
// maybe block `operator=`? contig_range follows reference semantics
// and there really isn't a run time safe `operator=` for reference semantics on
// a range when the RHS is of unknown width...
// I guess I could make it follow pointer semantics and rebase? Dunno
// this being tricky, I am tempted to =delete operator=
template<typename T, std::size_t N>
contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, std::size_t N>
contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, typename A>
contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
};
void mulArrayImpl( contig_range<int> arr, const int multiplier );
template<std::size_t N>
void mulArray( std::array<int, N>& arr, const int multiplier ) {
mulArrayImpl( contig_range<int>(arr), multiplier );
}
(未经测试,但设计应该有效)。
然后,在您的.cpp
文件中:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
这样做的缺点是循环遍历数组内容的代码(在编译时)不知道数组有多大,这可能会花费优化。它的优点是实现不必在标题中。
显式构造 a 时要小心contig_range
,就好像你传递它 aset
一样,它会假定set
数据是连续的,这是错误的,并且在整个地方都执行未定义的行为。唯一可以保证在其上工作的两个std
容器是vector
和array
(以及 C 风格的数组,碰巧!)。 deque
尽管随机访问不是连续的(危险的是,它在小块中是连续的!),list
甚至不接近,并且关联(有序和无序)容器同样不连续。
所以我实现的三个构造函数 wherestd::array
和std::vector
C 风格的数组,基本上涵盖了基础。
实施[]
也很容易,并且介于两者之间for()
是[]
您想要的大部分array
,不是吗?