给定类模板cArray
,有两个构造函数:
1.一个接受一个std::size
参数,
1.它接受任意数量的参数(假设它们是constructible fromT
)。
提问
如何修改cArray
,使其在给定单个整数文字时使用第一个(单参数)构造函数,而不将转换为std::size_t
?
- 从概念的Angular 来看,这里的要点是什么?
示例: cArray<int> arr1(7)
:调用可变参数构造函数,得到一个包含一个元素的cArray<int>
(7)。cArray<int> arr1((std::size_t)7)
:行为正确(但总是强制转换不方便)。
代码
godboltcArray.hpp
template <typename T>
class cArrayIterator;
template <typename T>
class cArray
{
public:
using value_type = T;
using array_type = cArray<T>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = value_type*;
using const_pointer = value_type const*;
using iterator = cArrayIterator<T>;
using const_iterator = cArrayIterator<const T>;
cArray(std::size_t _size)
{
if (_size > 0)
{
m_size = _size;
m_arr = new T[_size];
}
else
{
throw std::runtime_error("TO DO: array length cannot be 0!");
}
}
template <typename... Elements>
requires(std::constructible_from<T, Elements>&&...)
cArray(Elements&&... es)
: m_size{ sizeof...(es) }
, m_arr{ new T[sizeof...(es)] { es... } }
{}
// special member functions
cArray(const cArray& _other)
{
m_size = _other.size();
m_arr = new T[m_size];
std::copy_n(_other.m_arr, m_size, m_arr);
}
cArray(cArray&& _other) noexcept
: m_size(std::exchange(_other.m_size, 0))
, m_arr(std::exchange(_other.m_arr, nullptr))
{}
~cArray()
{
delete[] m_arr;
}
cArray& operator=(const cArray& _other)
{
delete[] m_arr;
m_size = _other.m_size;
m_arr = new T[m_size];
std::copy_n(_other.m_arr, m_size, m_arr);
return *this;
}
cArray& operator=(cArray&& _other) noexcept
{
delete[] m_arr;
m_size = std::exchange(_other.m_size, 0);
m_arr = std::exchange(_other.m_arr, nullptr);
return *this;
}
constexpr value_type& at(const size_type _index)
{
if (_index < m_size)
{
return m_arr[_index];
}
else
{
throw std::out_of_range("TO DO: index out of bounds."); // TO DO: custom exception
}
}
constexpr const_reference back() const noexcept
{
return m_arr[m_size - 1];
}
constexpr const_reference front() const noexcept
{
return m_arr[(size_type)0];
}
iterator begin()
{
return iterator(*this, 0);
}
iterator end()
{
return iterator(*this, m_size);
}
const_iterator begin() const
{
return const_iterator(*this, 0);
}
const_iterator end() const
{
return const_iterator(*this, m_size);
}
constexpr size_type size() const noexcept
{
return m_size;
}
constexpr T& operator[](const size_type _pos)
{
return m_arr[_pos];
}
constexpr const T& operator[](const size_type _pos) const
{
return m_arr[_pos];
}
private:
friend cArrayIterator<T>;
friend cArrayIterator<T const>;
std::size_t m_size;
T* m_arr;
};
template<class T>
cArray(const T&, const T&) -> cArray<T&>;
template<class T>
explicit cArray(T&&, T&&)->cArray<T>;
template <typename T>
class cArrayIterator
{
using array_type = std::conditional_t<std::is_const_v<T>, const cArray<std::remove_const_t<T>>, cArray<T>>;
public:
using value_type = std::remove_const_t<T>;;
using value_const_type = std::add_const_t<T>;
using iterator_type = cArrayIterator<T>;
using iterator_const_type = cArrayIterator<const T>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = value_type*;
using const_pointer = const value_type*;
using iterator_category = std::random_access_iterator_tag;
// constructor(s)
explicit cArrayIterator(array_type& _array, size_type const _index)
: m_array_ref(_array)
, m_index(_index)
{}
auto operator<=>(const cArrayIterator&) const = default;
iterator_type& operator=(const cArrayIterator& _other)
{
m_array_ref = _other.m_array_ref.get();
m_index = _other.m_index;
return *this;
}
iterator_type& operator=(cArrayIterator&& _other) noexcept
{
// Copy the data pointer and its length from the
// source object.
m_array_ref = _other.m_array_ref;
m_index = _other.m_index;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
_other._data = nullptr;
_other._length = 0;
m_array_ref = std::move(_other.m_array_ref);
m_index = _other.m_index;
return *this;
}
bool operator==(iterator_type const& _other) const
{
return ((m_array_ref.get().m_arr == _other.m_array_ref.get().m_arr) &&
(m_index == _other.m_index));
}
bool operator!=(iterator_type const& _other) const
{
return ((m_array_ref.get().m_arr != _other.m_array_ref.get().m_arr) ||
(m_index != _other.m_index));
}
const_reference operator*() const
{
// make sure array is within bounds
if ((m_index < 0) || (m_index >= m_array_ref.get().m_size))
{
throw std::logic_error("TO DO: Cannot dereferentiate the iterator");
}
return m_array_ref.get().m_arr[m_index];
}
pointer operator->() const
{
// make sure array is within bounds
if ((m_index < 0) || (m_index >= m_array_ref.get().m_size))
{
throw std::logic_error("TO DO: Cannot dereferentiate the iterator");
}
return &(m_array_ref.get().m_arr[m_index]);
}
iterator_type& operator++()
{
if (m_index >= m_array_ref.get().m_size)
{
throw std::out_of_range("TO DO: index out of bounds!");
}
m_index++;
return *this;
}
iterator_type operator++(int)
{
iterator_type temp = *this;
++* this;
return temp;
}
iterator_type& operator--()
{
if (m_index <= 0)
{
throw std::out_of_range("TO DO: index out of bounds!");
}
m_index--;
return *this;
}
iterator_type operator--(int)
{
iterator_type temp = *this;
--* this;
return temp;
}
iterator_type operator+(difference_type _other) const
{
iterator_type temp = *this;
return temp += _other;
}
difference_type operator+(iterator_type const& _other) const
{
return m_index + _other.m_index;
}
iterator_type operator-(difference_type _offset) const
{
iterator_type temp = *this;
return temp -= _offset;
}
difference_type operator-(iterator_type const& _other) const
{
return m_index - _other.m_index;
}
iterator_type& operator+=(const difference_type _offset)
{
difference_type next = m_index + _offset;
if (next >= m_array_ref.get().m_size)
{
throw std::out_of_range("TO DO: Iterator cannot be incremented past the bounds of the range");
}
m_index = next;
return *this;
}
iterator_type& operator-=(const difference_type _offset)
{
difference_type next = m_index - _offset;
if (next > 0)
{
throw std::out_of_range("TO DO: Iterator cannot be incremented past the bounds of the range");
}
m_index = next;
return *this;
}
value_type& operator[](size_type _index) const
{
if (_index >= m_array_ref.get().m_size)
{
throw std::out_of_range("TO DO: index out of range.");
}
return (m_array_ref.get().m_arr + _index);
}
private:
std::reference_wrapper<array_type> m_array_ref;
size_type m_index = 0;
};
cArrayImpl.cpp
template class DArray<int>;
template class DArray<std::string>;
main.cpp
#include <iostream>
#include <string>
#include ".\cArray.hpp"
#include ".\cArray_tests.cpp"
#include ".\cArrayImpl.cpp"
int
main(int argc, char ** argv)
{
cArray<int> arr1((std::size_t)10);
std::cout << "cArray<int> WITH cast to std::size (expected 10): " << arr1.size() << std::endl;
cArray<int> arr2(10);
std::cout << "cArray<int> WITHOUT cast to std::size (expected 10): " << arr2.size() << std::endl;
//cArray<double> arr3(10);
std::cout << "cArray<double> WITHOUT cast = ERROR" << std::endl;
}
我试过演绎指南,在SO上读了大约10个问题,但我无法
1条答案
按热度按时间nfg76nw01#
你可以给变量构造函数添加更多的限制:
当
sizeof...(Elements) == 1 && (std::convertible_to<Elements, std::size_t> && ...)
时,您希望删除重载。所以
Demo
您可能还需要将类型转换为
CArray
和Elements
。提供标记/命名构造函数是一个不错的选择。