My code creates arrays, I need to implement deletions for it, but I don’t know how to do it beautifully and correctly.
main code
template<class T1>
auto auto_vector(T1&& _Size) {
return new int64_t[_Size]{};
}
template <class T1, class... T2>
auto auto_vector(T1&& _Size, T2&&... _Last)
{
auto result = new decltype(auto_vector(_Last...))[_Size];
for (int64_t i = 0; i < _Size; ++i) {
result[i] = auto_vector(_Last...);
}
return result;
}
this is the code that I want to combine with the first
template <class T1, class T2, class T3, class T4>
void del_vector(T4& _Del, T1& _Size, T2& _Size2, T3& _Size3) {
for (ptrdiff_t i = 0; i < _Size3; ++i) {
for (ptrdiff_t k = 0; k < _Size2; ++k) {
delete _Del[i][k];
}
delete _Del[i];
}
delete _Del;
}
int main()
{
auto map1 = auto_vector(_Size, _Size2, _Size3);
auto map2 = auto_vector(3, 4, 5, 7);
del_vector(map1, _Size, _Size2, _Size3);
return 0;
}
I do not like this option I would like something like that.
int main()
{
auto_vector map1(_Size, _Size2, _Size3);
del_vector map1(_Size, _Size2, _Size3);
//or so
auto_vector<_Size, _Size2, _Size3> map1;
del_vector<_Size, _Size2, _Size3> map1;
return 0;
}
the reason why I do this is because I cannot implement the same thing using just a vector
and I don’t understand why the vector does not work with dynamic arrays, the fact is that I do not know the exact data
_Size, _Size2, _Size3 = ? before compilation.
therefore I use new and all this I do only for his sake.
if it is useful to you to look at the data for tests
cout << " ---------TEST---------- " << endl;
for (ptrdiff_t i = 0; i < _Size3; ++i) {
for (ptrdiff_t k = 0; k < _Size2; ++k) {
for (ptrdiff_t j = 0; j < _Size; ++j) {
cout << map1[i][k][j] << " ";
}
cout << endl;
}
cout << endl;
}
cout << " ---------TEST---------- " << endl;
You have too many new operations in the code. Also del_vector doesn't make any sense in your preferred version as any decent class will deallocate its data in the destructor (lest it has no ownership over it).
What you need is to make a class or a template class that wraps things up.
#include <iostream>
#include <vector>
#include <array>
#include <type_traits>
using namespace std;
template<size_t index, size_t dim>
void ModifyArray(std::array<size_t,dim>& lcAarray){}
template<size_t index, size_t dim, typename... Args>
void ModifyArray(std::array<size_t, dim>& lcAarray, size_t arg, Args... args)
{
lcAarray[index] = arg;
ModifyArray<index+1>(lcAarray, args...);
}
template<typename... Args>
std::array<size_t, sizeof...(Args)> MakeArray(Args... args)
{
std::array<size_t, sizeof...(Args)> lclArray;
ModifyArray<0>(lclArray, args...);
return lclArray;
}
template< std::size_t dim >
class myMultiArray;
template<std::size_t dim, std::size_t crDim>
class MyMultiArrayIterator
{
public:
MyMultiArrayIterator(myMultiArray<dim>* multiArray, size_t index):
m_pMultiArray(multiArray),
m_index(index)
{}
template<size_t newDim = crDim+1, typename std::enable_if<newDim < dim, int>::type = 0>
MyMultiArrayIterator<dim, newDim> operator [] (size_t idx)
{
return MyMultiArrayIterator<dim, newDim>(m_pMultiArray, m_index + idx*m_pMultiArray->GetStep(crDim));
}
template<size_t newDim = crDim+1, typename std::enable_if<newDim == dim, int>::type = 0>
int& operator [] (size_t idx)
{
return m_pMultiArray->GetValue(m_index+idx*m_pMultiArray->GetStep(crDim));
}
private:
size_t m_index;
myMultiArray<dim>* m_pMultiArray;
};
template< std::size_t dim >
class myMultiArray
{
public:
myMultiArray() = default;
template<class... Args, typename std::enable_if<sizeof...(Args) == dim-1, int>::type = 0>
myMultiArray(size_t size0, Args... args)
{
m_sizes = MakeArray(size0, args...);
std::size_t uTotalSize = 1;
for (std::size_t i = 0; i < dim; i++)
{
m_steps[i] = uTotalSize;
uTotalSize *= m_sizes[i];
}
std::cout << uTotalSize << "\n";
m_data.resize(uTotalSize);
}
// resizes m_data to multiplication of sizes
int operator () (std::array < std::size_t, dim > indexes) const
{
return m_data[computeIndex(indexes)];
}
int &operator () (std::array < std::size_t, dim > indexes)
{
return m_data[computeIndex(indexes)];
}
// modify operator
// you'll probably need more utility functions for such a multi dimensional array
int GetValue(size_t index) const
{
return m_data[index];
}
int &GetValue(size_t index)
{
return m_data[index];
}
size_t GetSize(size_t index) const
{
return m_sizes[index];
}
size_t GetStep(size_t index) const
{
return m_steps[index];
}
MyMultiArrayIterator<dim, 1> operator [] (size_t index)
{
return MyMultiArrayIterator<dim, 1>(this, index*m_steps[0]);
}
private:
size_t computeIndex(std::array < std::size_t, dim > indexes)
{
size_t location = 0;
for(size_t i=0; i< dim; i++)
{
location += m_steps[i]*indexes[i];
}
return location;
}
private:
std::vector < int > m_data;
std::array < std::size_t, dim > m_sizes;
std::array < std::size_t, dim > m_steps;
};
template<typename... Args>
myMultiArray<sizeof...(Args)> MakeMyMultiArray(Args... args)
{
return myMultiArray<sizeof...(Args)>(args...);
}
int main ()
{
auto mapMA = MakeMyMultiArray(3,4,5);
mapMA({2ull,3ull,4ull}) = 7;
std::cout << mapMA({{2ull,3ull,4ull}}) << "\n";
std::cout << mapMA[2][3][4];
return 0;
}
Related
I tried to create a template for a generic 2D array, which would allow me to create arrays of different data types and fill them with random values. My current code seemingly creates three objects, but fills them with the same random values, and the double type massive does not even have double values. I think the problem is somewhere in the constructor and with the pointers, but I am not sure how to fix this.
My class:
template <typename T>
class MATRIX
{
private:
T** M;
int m = 8;
int n = 12;
public:
MATRIX(T matr[8][12]);
void fill();
};
Constructor:
template <typename T>
MATRIX<T>::MATRIX(T matr[8][12]){
M = (T**) new T*[m];
for (int i = 0; i < m; i++)
M[i] = (T*)new T[n];
}
Method:
template <typename T>
void MATRIX<T>::fill(){
T randomNumber;
srand((unsigned) time(0));
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
randomNumber = (rand() % (122 + 1 - 65)) + 65;
M[i][j] = randomNumber;} } }
Main:
int main() {
int intMatr[8][12];
MATRIX<int>a(intMatr);
a.fill();
double doubleMatr[8][12];
MATRIX<double>b(doubleMatr);
b.fill();
char charMatr[8][12];
MATRIX<char>c(charMatr);
c.fill();
return 0; }
Not really a direct answer to your question, howeverr try not to use new/delete if you don't have to as is shown in this example (note the array2d_t class is something I wrote earlier and reused for this example so it can do a bit more then needed)
I also show how to use c++'s random generators to create characters for your matrix.
#pragma once
#include <vector>
#include <iostream>
#include <random>
#include <utility>
#include <string>
#include <stdexcept>
//---------------------------------------------------------------------------------------------------------------------
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
struct array2d_t
{
constexpr array2d_t() :
m_values{}
{
}
constexpr explicit array2d_t(const type_t(&values)[rows_v][cols_v])
{
// constexpr compatible initialization
for (auto row = 0; row < rows_v; ++row)
{
for (auto col = 0; col < cols_v; ++col)
{
m_values[row][col] = values[row][col];
}
}
}
~array2d_t() = default;
// return a row
constexpr auto operator[](const std::size_t row)
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return row_t(&m_values[row][0]);
}
// return a const row
constexpr auto operator[](const std::size_t row) const
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return const_row_t(&m_values[row][0]);
}
// return iterator to the first row (so array can be used in range based for loop)
constexpr auto begin()
{
return std::begin(m_values);
}
// return iterator to the last row (so array can be used in range based for loop)
constexpr auto end()
{
return std::end(m_values);
}
constexpr std::size_t rows() const
{
return rows_v;
}
constexpr std::size_t columns() const
{
return cols_v;
}
private:
//-----------------------------------------------------------------------------------------------------------------
/// row helper
struct row_t
{
constexpr row_t(type_t* row) :
m_row{ row }
{
}
constexpr type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
type_t* m_row;
};
//-----------------------------------------------------------------------------------------------------------------
// row helper for const
struct const_row_t
{
constexpr const_row_t(const type_t* row) :
m_row{ row }
{
}
constexpr const type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
const type_t* m_row;
};
type_t m_values[rows_v][cols_v];
};
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
std::ostream& operator<<(std::ostream& os, array2d_t<type_t,rows_v,cols_v>& arr)
{
for (const auto& row : arr)
{
bool comma = false;
for (const auto& value : row)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
std::cout << "\n";
return os;
}
//---------------------------------------------------------------------------------------------------------------------
class MATRIX :
public array2d_t<char, 8, 12>
{
public:
void fill()
{
// initialize a vector of valid character for random to pick from
// static ensures this is only done on first call to function
static std::vector<char> valid_chars = []
{
std::vector<char> chars;
chars.reserve(52);
for (char c = 'A'; c < 'Z'; ++c) chars.push_back(c);
for (char c = 'a'; c < 'z'; ++c) chars.push_back(c);
return chars;
}();
// this is how to setup random number generation in C++
static std::random_device rd{};
static std::default_random_engine random{ rd() };
static std::uniform_int_distribution<std::size_t> distribution(0, valid_chars.size() - 1);
for (auto& row : *this)
{
for (auto& value : row)
{
value = valid_chars[distribution(random)];
}
}
}
};
//---------------------------------------------------------------------------------------------------------------------
int main()
{
MATRIX m;
m.fill();
std::cout << m;
return 0;
}
I have an integer N which I know at compile time. I also have an std::array holding integers describing the shape of an N-dimensional array. I want to generate nested loops, as described bellow, at compile time, using metaprogramming techniques.
constexpr int N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
auto f = [/* accept object which uses coords */] (auto... coords) {
// do sth with coords
};
// This is what I want to generate.
for(int i = 0; i < shape[0]; i++) {
for(int j = 0; j < shape[1]; j++) {
for(int k = 0; k < shape[2]; k++) {
for(int l = 0; l < shape[3]; l++) {
f(i,j,k,l) // object is modified via the lambda function.
}
}
}
}
Note the parameter N is known at compile time but might change unpredictably between compilations, hence I can't hard code the loops as above. Ideally the loop generation mechanism will provide an interface which accepts the lambda function, generates the loops and calls the function producing the equivalent code as above. I am aware that one can write an equivalent loop at runtime with a single while loop and an array of indices, and there are answers to this question already. I am, however, not interested in this solution. I am also not interested in solutions involving preprocessor magic.
Something like this (NOTE: I take the "shape" as a variadic template argument set..)
#include <iostream>
template <int I, int ...N>
struct Looper{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
Looper<N...>()(f, x..., i);
}
}
};
template <int I>
struct Looper<I>{
template <typename F, typename ...X>
constexpr void operator()(F& f, X... x) {
for (int i = 0; i < I; ++i) {
f(x..., i);
}
}
};
int main()
{
int v = 0;
auto f = [&](int i, int j, int k, int l) {
v += i + j + k + l;
};
Looper<1, 3, 5, 2>()(f);
auto g = [&](int i) {
v += i;
};
Looper<5>()(g);
std::cout << v << std::endl;
}
Assuming you don't want total loop unrolling, just generation of i, j, k etc. argument tuples for f:
#include <stdio.h>
#include <utility> // std::integer_sequence
template< int dim >
constexpr auto item_size_at()
-> int
{ return ::shape[dim + 1]*item_size_at<dim + 1>(); }
template<> constexpr auto item_size_at<::N-1>() -> int { return 1; }
template< size_t... dim >
void call_f( int i, std::index_sequence<dim...> )
{
f( (i/item_size_at<dim>() % ::shape[dim])... );
}
auto main()
-> int
{
int const n_items = ::shape[0]*item_size_at<0>();
for( int i = 0; i < n_items; ++i )
{
call_f( i, std::make_index_sequence<::N>() );
}
}
I suppose this is exactly what you asked for:
#include <array>
#include <iostream>
constexpr int N{4};
constexpr std::array<int, N> shape {{1,3,5,2}};
// Diagnositcs
template<typename V, typename ...Vals>
struct TPrintf {
constexpr static void call(V v, Vals ...vals) {
std::cout << v << " ";
TPrintf<Vals...>::call(vals...);
}
};
template<typename V>
struct TPrintf<V> {
constexpr static void call(V v) {
std::cout << v << std::endl;
}
};
template<typename ...Vals>
constexpr void t_printf(Vals ...vals) {
TPrintf<Vals...>::call(vals...);
}
// Unroll
template<int CtIdx, typename F>
struct NestedLoops {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[CtIdx]; ++i) {
NestedLoops<CtIdx + 1, F>::call(f, idx..., i);
}
}
};
template<typename F>
struct NestedLoops<N-1, F> {
template<typename ...RtIdx>
constexpr static void call(const F& f, RtIdx ...idx) {
for(int i = 0; i < shape[N-1]; ++i) {
f(idx..., i);
}
}
};
template<typename F>
void nested_loops(const F& f) {
NestedLoops<0, F>::call(f);
}
int main()
{
auto lf = [](int i, int j, int k, int l) {
t_printf(i,j,k,l);
};
nested_loops(lf);
return 0;
}
Another variant of the same thing:
template <size_t shape_index, size_t shape_size>
struct Looper
{
template <typename Functor>
void operator()(const std::array<int, shape_size>& shape, Functor functor)
{
for (int index = 0; index < shape[shape_index]; ++index)
{
Looper<shape_index + 1, shape_size>()
(
shape,
[index, &functor](auto... tail){ functor(index, tail...); }
);
}
}
};
template <size_t shape_size>
struct Looper<shape_size, shape_size>
{
template <typename Functor>
void operator()(const std::array<int, shape_size>&, Functor functor)
{
functor();
}
};
template <size_t shape_size, typename Functor>
void loop(const std::array<int, shape_size>& shape, Functor functor)
{
Looper<0, shape_size>()(shape, functor);
}
Example of use:
constexpr size_t N {4};
constexpr std::array<int, N> shape {{1,3,5,2}};
void f(int i, int j, int k, int l)
{
std::cout
<< std::setw(5) << i
<< std::setw(5) << j
<< std::setw(5) << k
<< std::setw(5) << l
<< std::endl;
}
// ...
loop(shape, f);
Live demo
I have below data structure,
typedef vector< tuple<int,int,int> > vector_tuple;
In vector i am storing tuple<value,count,position>
I want to sort my vector based on count, If count is same then based on position sort the vector.
structure ordering
{
bool ordering()(....)
{
return /// ?
}
};
int main()
{
std::vector<int> v1{1,1,1,6,6,5,4,4,5,5,5};
std::vector<int> v2(v1);
vector_tuple vt;
std::tuple<int,int,int> t1;
std::vector<int>::iterator iter;
int sizev=v1.size();
for(int i=0; i < sizev ; i++)
{
auto countnu = count(begin(v2),end(v2),v1[i]);
if(countnu > 0)
{
v2.erase(std::remove(begin(v2),end(v2),v1[i]),end(v2));
auto t = std::make_tuple(v1[i], countnu, i);
vt.push_back(t);
}
}
sort(begin(vt),end(vt),ordering(get<1>vt); // I need to sort based on count and if count is same, sort based on position.
for (int i=0; i < vt.size(); i++)
{
cout << get<0>(vt[i]) << " " ;
cout << get<1>(vt[i]) << " " ;
cout << get<2>(vt[i]) << " \n" ;
}
}
Your compare method should look like:
auto ordering = [](const std::tuple<int, int, int>& lhs,
const std::tuple<int, int, int>& rhs) {
return std::tie(std::get<1>(lhs), std::get<2>(lhs))
< std::tie(std::get<1>(rhs), std::get<2>(rhs));
};
std::sort(std::begin(vt), std::end(vt), ordering);
All credit to Jarod42 for the std::tie answer.
Now let's make it generic by creating a variadic template predicate:
template<std::size_t...Is>
struct tuple_parts_ascending
{
template<class...Ts>
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return sort_order(l) < sort_order(r);
}
};
which we can invoke thus:
sort(begin(vt),end(vt),tuple_parts_ascending<1,2>());
Full Code:
#include <vector>
#include <algorithm>
#include <tuple>
#include <iostream>
using namespace std;
typedef std::vector< std::tuple<int,int,int> > vector_tuple;
template<std::size_t...Is>
struct tuple_parts_ascending
{
template<class...Ts>
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return sort_order(l) < sort_order(r);
}
};
int main()
{
std::vector<int> v1{1,1,1,6,6,5,4,4,5,5,5};
std::vector<int> v2(v1);
vector_tuple vt;
std::tuple<int,int,int> t1;
std::vector<int>::iterator iter;
int sizev=v1.size();
for(int i=0; i < sizev ; i++)
{
auto countnu = count(begin(v2),end(v2),v1[i]);
if(countnu > 0)
{
v2.erase(std::remove(begin(v2),end(v2),v1[i]),end(v2));
auto t = std::make_tuple(v1[i], countnu, i);
vt.push_back(t);
}
}
sort(begin(vt),end(vt),tuple_parts_ascending<1,2>());
for (int i=0; i < vt.size(); i++)
{
cout << get<0>(vt[i]) << " " ;
cout << get<1>(vt[i]) << " " ;
cout << get<2>(vt[i]) << " \n" ;
}
}
Expected results:
6 2 3
4 2 6
1 3 0
5 4 5
Going further, we could make this operation a little more generic and 'library-worthy' by allowing the ordering predicate and the indices to be passed as parameters (this solution required c++14):
namespace detail {
template<class Pred, std::size_t...Is>
struct order_by_parts
{
constexpr
order_by_parts(Pred&& pred)
: _pred(std::move(pred))
{}
template<class...Ts>
constexpr
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
constexpr
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return _pred(sort_order(l), sort_order(r));
}
private:
Pred _pred;
};
}
template<class Pred, size_t...Is>
constexpr
auto order_by_parts(Pred&& pred, std::index_sequence<Is...>)
{
using pred_type = std::decay_t<Pred>;
using functor_type = detail::order_by_parts<pred_type, Is...>;
return functor_type(std::forward<Pred>(pred));
}
Now we can sort like so:
sort(begin(vt),end(vt),
order_by_parts(std::less<>(), // use predicate less<void>
std::index_sequence<1, 2>())); // pack indices into a sequence
Using lambdas:
std::sort(std::begin(vt),std::end(vt),[](const auto& l,const auto& r){
if(std::get<1>(l)== std::get<1>(r)){
return std::get<2>(l) < std::get<2>(r);
}
return std::get<1>(l) < std::get<1>(r);
});
I was trying my hand with allocators this time & felt that there were many chances of leaking the resources. So I thought what if I used std::unique_ptr to handle them. I tried my hand with a std::vector's allocator. My code goes like this :-
// allocator
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class X
{
int x,ID;
static int i;
public:
X()
{
cout<<"constructing ";
ID=++i;
cout<<"ID="<<ID<<'\n';
}
X(int a)
{
x=a;
cout<<"constructing ";
ID=++i;
cout<<"ID="<<ID<<'\n';
}
void get()
{
cout<<"enter x: ";
cin>>x;
}
void disp()
{
cout<<"x="<<x<<'\t';
}
~X()
{
cout<<"destroying ID="<<ID<<'\n';
}
};
int X:: i=0;
int main()
{
ios::sync_with_stdio(false);
vector<X> v;
auto alloc = v.get_allocator();
unsigned int i=0;
X *p(alloc.allocate(5));
for (i=0;i<5;++i)
alloc.construct (&p[i], i+1);
unique_ptr<X[]> ptr(p);
cout<<"\nthe elements are:-\n";
for (i=0;i<5;++i)
{
ptr[i].disp();
cout << '\t' << (long long)alloc.address(ptr[i]) << '\n';
}
cout<<"\n";
/*for (i=0;i<5;++i)
alloc.destroy(&p[i]);
deallocate(p,16)*/
return 0;
}
Unfortunately this code crashes showing UB. So what should I do ? How should I manipulate my code so as to make it suited for std::unique_ptr ?
template<typename T>
std::unique_ptr<T[], std::function<void(T *)>> make_T(X *ptr, std::allocator<T> alloc, std::size_t size) {
auto deleter = [](T *p, std::allocator<T> alloc, std::size_t size) {
for (int i = 0; i < size; ++i) {
alloc.destroy(&p[i]);
}
alloc.deallocate(p, sizeof(T) * size);
};
return {ptr, std::bind(deleter, std::placeholders::_1, alloc, size)};
}
int main(int argc, const char * argv[]) {
std::allocator<X> alloc = std::allocator<X>();
X *p = alloc.allocate(5);
for (int i = 0; i < 5; ++i) {
alloc.construct(&p[i], i + 1);
}
auto ptr = make_T(p, alloc, 5);
return 0;
}
Can also write one to construct the objects for you:
template<typename T, typename... Args>
std::unique_ptr<T[], std::function<void(T *)>> make_T_Construct(std::allocator<T> alloc, std::size_t size, Args... args) {
X *ptr = alloc.allocate(size);
for (std::size_t i = 0; i < size; ++i) {
alloc.construct(&ptr[i], std::forward<Args>(args)...);
}
auto deleter = [](T *p, std::allocator<T> alloc, std::size_t size) {
for (std::size_t i = 0; i < size; ++i) {
alloc.destroy(&p[i]);
}
alloc.deallocate(p, sizeof(T) * size);
};
return {ptr, std::bind(deleter, std::placeholders::_1, alloc, size)};
}
int main(int argc, const char * argv[]) {
std::allocator<X> alloc = std::allocator<X>();
auto ptr = make_T_Construct(alloc, 5, 100);
return 0;
}
Edit: To do what you want (tracking allocations), you have to track the memory allocations yourself using a custom allocator..
template<typename T>
struct Allocator
{
typedef T value_type;
Allocator() noexcept {};
template<typename U>
Allocator(const Allocator<U>& other) throw() {};
T* allocate(std::size_t n, const void* hint = 0)
{
T* memory = static_cast<T*>(::operator new(n * (sizeof(T) + sizeof(bool))));
for (std::size_t i = 0; i < n * (sizeof(T) + sizeof(bool)); ++i)
{
*reinterpret_cast<bool*>(reinterpret_cast<char*>(memory) + sizeof(bool)) = false;
}
return memory;
}
void deallocate(T* ptr, std::size_t n)
{
::operator delete(ptr);
}
void construct(T* p, const T& arg)
{
destroy(p);
new(p) T(arg);
*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = true;
}
template<class U, class... Args>
void construct(U* p, Args&&... args)
{
destroy(p);
::new(p) U(std::forward<Args>(args)...);
*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = true;
}
void destroy(T* p)
{
if (*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool))) {
p->~T();
*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = false;
}
}
template<class U>
void destroy(U* p)
{
if (*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool))) {
p->~U();
*reinterpret_cast<bool*>(reinterpret_cast<char*>(p) + sizeof(bool)) = false;
}
}
};
template <typename T, typename U>
inline bool operator == (const Allocator<T>&, const Allocator<U>&)
{
return true;
}
template <typename T, typename U>
inline bool operator != (const Allocator<T>& a, const Allocator<U>& b)
{
return !(a == b);
}
I am implementing a simple circular vector class. I want to implement an emplace member function, but I am getting an error which I don't understand. It might be a simple fix for something I am doing wrong, but since I don't have much experience with variadic templates, I can't figure out what...
The error I am getting is:
main.cpp: In function 'int main()':
main.cpp:104:50: error: no matching function for call to 'CircularVector<Item>::emplace(int, int, int, int, int, int, std::vector<int>, int)'
v.emplace(1, 0, 1, 0, 1, 0, vector<int>(), -1);
^
main.cpp:104:50: note: candidate is:
main.cpp:20:7: note: void CircularVector<T, Args>::emplace(const Args& ...) [with T = Item; Args = {}]
void emplace(const Args &... args) {
^
main.cpp:20:7: note: candidate expects 0 arguments, 8 provided
The source code generating this error is (also located here http://coliru.stacked-crooked.com/a/37d50d6f23363357):
#include <vector>
using namespace std;
#define CIRCULAR_BUFFER_DEFAULT_SIZE 5000
template <typename T, typename ...Args>
class CircularVector {
public:
CircularVector(int size) {
_size = size;
_v.reserve(_size);
}
CircularVector() {
_size = CIRCULAR_BUFFER_DEFAULT_SIZE;
_v.reserve(_size);
}
void emplace(const Args &... args) {
++Count;
++_indexWrite;
if (_indexWrite > _size - 1) _indexWrite = 0;
_v.emplace(_indexWrite, args...);
}
void push(const T& item) {
++Count;
++_indexWrite;
if (_indexWrite > _size - 1) _indexWrite = 0;
_v[_indexWrite] = item;
}
void pop(T& item) {
item = _v[_indexRead];
++_indexRead;
if (_indexRead > _size - 1) _indexRead = 0;
--Count;
}
T& back() {
return _v[(_indexRead + Count - 1) % _size];
}
void erase(int numItems) {
_indexRead += numItems;
if (_indexRead > _size - 1) _indexRead -= _size;
Count -= numItems;
}
void eraseAt(int index) {
swap(_v[index], _v[(_indexRead + Count - 1) % _size]);
--Count;
--_indexWrite;
if (_indexWrite < 0) {
_indexWrite = _size - 1;
}
}
void clear() {
_indexRead = 0;
_indexWrite = -1;
Count = 0;
}
T& operator[](std::size_t idx) {
int index = _indexRead + idx;
if (index > _size) index = index % _size;
return _v[index];
};
int Count = 0;
private:
int _indexWrite = -1;
int _indexRead = 0;
int _size = 0;
std::vector<T> _v;
};
class Item {
public:
double A;
int B;
int C;
vector<int> D;
int E;
Item(double a, int b, int c, vector<int> &d, int e) {
A = a;
B = b;
C = c;
D = d;
E = e;
}
};
int main() {
CircularVector<Item> v;
v.emplace(1, 0, 1, 0, 1, 0, vector<int>(), -1);
}
In case anyone stumbles upon the same issue, this is how I achieved this:
void emplace(Args&&... args) {
++Count;
++_indexWrite;
if (_indexWrite > _size - 1) _indexWrite = 0;
_v.emplace(_v.begin() + _indexWrite, std::forward<Args>(args)...);
}
Although what I really wanted was to construct an element using the reserved memory in that index, and not inserting a new element at that specific position.
Args has to be a template parameter of emplace, not CircularVector.
template <typename T>
class CircularVector {
public:
/* ... */
template<typename ...Args>
void emplace(const Args &... args) {
/* ... */
}
};
Also, you should consider using forwarding references for emplace.