Problems creating a buffer in C++ - c++

I have create a buffer structure like this:
template <typename T>
class locked_buffer {
public:
locked_buffer(int n);
locked_buffer(const locked_buffer &) = delete;
~locked_buffer() = default;
int size() const noexcept;
bool empty() const noexcept;
bool full() const noexcept;
void put(const T & x, bool last) noexcept;
std::pair<bool,T> get() noexcept;
private:
int next_position(int p) const noexcept;
bool do_empty() const noexcept;
bool do_full() const noexcept;
private:
struct item {
bool last;
T value;
};
const int size_;
std::unique_ptr<item[]> buf_;
int next_read_ = 0;
int next_write_ = 0;
mutable std::mutex mut_;
std::condition_variable not_full_;
std::condition_variable not_empty_;
};
template <typename T>
locked_buffer<T>::locked_buffer(int n) :
size_{n},
buf_{new item[size_]}
{
}
template <typename T>
int locked_buffer<T>::size() const noexcept
{
return size_;
}
But when I try to use it in my main function,
locked_buffer <std::pair<int, std::vector<std::vector<unsigned char>>>> buffer1;
I obtain an error like this:
error: missing template arguments before ‘std’ locked_buffer <std::pair<int, std::vector<std::vector<unsigned char>>>>buffer1;
I think is probably I'm not creating the template properly, but at this point I'm very frustated because I can't reach any proper solution.
Thanks.

As #TomaszPlaskota said, I created an object of type locked_buffer with n elements, where 'n' represents the size of the buffer that I'm creating.
locked_buffer <std::pair<int, std::vector<std::vector<unsigned char>>>> buffer1(n);

Related

error use of deleted function when trying to pass rvalue to a tuple

Original context:
I am trying to pass a tuple of (object, expected_value_of_some_property) to a test function
I created a simple class to reproduce the error I am facing:
template <typename T>
class Vector
{
private:
size_t m_size;
std::unique_ptr<std::vector<int>> m_vector;
public:
Vector();
Vector(const Vector<int>&);
~Vector() = default;
void push_back(T);
T get(int) const;
size_t size() const;
};
template <typename T>
Vector<T>::Vector()
:m_size(0),
m_vector(new std::vector<T>)
{}
template <typename T>
Vector<T>::Vector(const Vector<int>& v)
:m_size(v.size()),
m_vector(new std::vector<T>)
{
for (size_t i = 0; i < v.size(); i++)
{
this->push_back(v.get(i));
}
}
template <typename T>
void Vector<T>::push_back(T value)
{
m_vector->push_back(value);
m_size ++;
}
template <typename T>
T Vector<T>::get(int index) const
{
return m_vector->operator[](index);
}
template <typename T>
size_t Vector<T>::size() const
{
return m_size;
}
The error is triggered when trying to produce a tuple of Vector object and an int somewhere in a test code:
int main(int argc, char const *argv[])
{
std::tuple<Vector<int>, int> vector_test;
vector_test = std::make_tuple(Vector<int>{}, 0);
int size = std::get<0>(vector_test);
Vector<int> vector = std::get<1>(vector_test);
// .. test code
return 0;
}
Output:
error: use of deleted function ‘std::tuple<Vector<int>, int>& std::tuple<Vector<int>, int>::operator=(const std::tuple<Vector<int>, int>&)’
20 | vector_test = std::make_tuple(Vector<int>{}, 0);
| ^ ^
What am I doing wrong here?
Since your Vector class has a unique_ptr member, that means your class itself has the copy-assignment implicitly deleted. Therefore this assignment will fail
std::tuple<Vector<int>, int> vector_test;
vector_test = std::make_tuple(Vector<int>{}, 0); // <--- this
Instead you can just directly initialize in one step
std::tuple<Vector<int>, int> vector_test = std::make_tuple(Vector<int>{}, 0);

Const correctness of STL library with reference-wrapper?

I have the following class:
class Data;
class A
{
public:
A(Data& _data) : data(_data) {}
Data& getData() {return data;}
const Data& getData() const {return data;}
private:
Data& data;
};
Now imagine I need to keep not one, but multiple instances of Data. I keep them in a vector of reference wrappers, but I would also like to keep the const correctness: pass the data as unmodifiable in const context.
class A
{
public:
void addData(Data& _data) {data.push_back(std::ref(_data));}
const std::vector<std::reference_wrapper<Data>>& getData() {return data;}
//doesn't compile
//const std::vector<std::reference_wrapper<const Data>>& getData() const {return data;}
private:
std::vector<std::reference_wrapper<Data>> data;
}
How to implement this without having physical copying of the data? I.e. I don't want to return a copy of the vector by value and I don't want to keep two separate vectors in class A. Both are performance-impacting solutions for what is basically just a semantic problem.
Here's a const propagating reference_wrapper, based on cppreference's possible implementation
#include <utility>
#include <functional>
#include <type_traits>
namespace detail {
template <class T> T& FUN(T& t) noexcept { return t; }
template <class T> void FUN(T&&) = delete;
}
template <class T>
class reference_wrapper {
public:
// types
typedef T type;
// construct/copy/destroy
template <class U, class = decltype(
detail::FUN<T>(std::declval<U>()),
std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>> && !std::is_same_v<reference_wrapper<const T>, std::remove_cvref_t<U>>>()
)>
reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
: _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
reference_wrapper(reference_wrapper&) noexcept = default;
reference_wrapper(reference_wrapper&&) noexcept = default;
// assignment
reference_wrapper& operator=(reference_wrapper& x) noexcept = default;
reference_wrapper& operator=(reference_wrapper&& x) noexcept = default;
// access
operator T& () noexcept { return *_ptr; }
T& get() noexcept { return *_ptr; }
operator const T& () const noexcept { return *_ptr; }
const T& get() const noexcept { return *_ptr; }
template< class... ArgTypes >
std::invoke_result_t<T&, ArgTypes...>
operator() ( ArgTypes&&... args ) {
return std::invoke(get(), std::forward<ArgTypes>(args)...);
}
template< class... ArgTypes >
std::invoke_result_t<const T&, ArgTypes...>
operator() ( ArgTypes&&... args ) const {
return std::invoke(get(), std::forward<ArgTypes>(args)...);
}
private:
T* _ptr;
};
template <class T>
class reference_wrapper<const T> {
public:
// types
typedef const T type;
// construct/copy/destroy
template <class U, class = decltype(
detail::FUN<const T>(std::declval<U>()),
std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>> && !std::is_same_v<reference_wrapper<T>, std::remove_cvref_t<U>>>()
)>
reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<const T>(std::forward<U>(u))))
: _ptr(std::addressof(detail::FUN<const T>(std::forward<U>(u)))) {}
reference_wrapper(const reference_wrapper<T>& o) noexcept
: _ptr(std::addressof(o.get())) {}
reference_wrapper(const reference_wrapper&) noexcept = default;
reference_wrapper(reference_wrapper&&) noexcept = default;
// assignment
reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
reference_wrapper& operator=(reference_wrapper&& x) noexcept = default;
// access
operator const T& () const noexcept { return *_ptr; }
const T& get() const noexcept { return *_ptr; }
template< class... ArgTypes >
std::invoke_result_t<const T&, ArgTypes...>
operator() ( ArgTypes&&... args ) const {
return std::invoke(get(), std::forward<ArgTypes>(args)...);
}
private:
const T* _ptr;
};
// deduction guides
template<class T>
reference_wrapper(T&) -> reference_wrapper<T>;
You can then add const qualified access via span.
class A
{
public:
void addData(Data& _data) {data.emplace_back(_data);}
std::span<reference_wrapper<Data>> getData() { return { data.data(), data.size() }; }
std::span<const reference_wrapper<Data>> getData() const { return { data.data(), data.size() }; }
private:
std::vector<reference_wrapper<Data>> data;
}
Note that you can't copy or move the const reference_wrapper<Data>s from the second getData, and there is only access to const Data &.
Consider the visitor pattern :
struct ConstVisitor {
virtual ~ConstVisitor() = default;
virtual bool visit(const Data & data) = 0;//returns true if search should keep going on
};
void A::accept(ConstVisitor & visitor) const;
This way it does not matter to the outside world what kind of container Data is stored in (here a std::vector). The visitor pattern is very similar to an Enumerator in C#.

Error: Class A is not a base of Class B C++

When I try to call the function in line **
through this function:
template<class T,int SIZE>
T const& Array<T,SIZE>::const_iterator::operator*() const {
return this->Array<T,SIZE>::iterator::operator*();
}
It gives me the following error:
error: 'Array<int, 3>::iterator' is not a base of 'const Array<int, 3>::const_iterator'
Can anyone explain why?
template <class T, int SIZE>
class Array {
T data[SIZE];
public:
explicit Array();
Array(const Array& a); //copy constructor
~Array(); //destructor
class iterator {
Array<T,SIZE>* array;
int index;
public:
iterator(Array<T,SIZE>* array,int index);
T& operator*() const; //**
};
class const_iterator {
const Array<T,SIZE>* array;
int index;
public:
T const& operator*() const;
};
}

Use assignment operator with subscript operator to assign value to std::map

I have a Matrix class
template <typename T>
class Matrix
{
public:
const size_t rows;
const size_t cols;
const std::map<std::array<int, 2>, T> data;
Matrix(int a, int b) : rows(a), cols(b)
{
}
};
which is initialized like this:
Matrix<double> M(5,5);
creating a 5x5 matrix.
I want to assign values to the map like so:
M[{1,2}] = 1;
How would I go about doing that in the most readable way? I'm not sure how to get the subscript and assignment operator working together.
Let's add some helper aliases to Matrix while we are at it
template <typename T>
class Matrix
{
// rather than stoping people changing the members via const
// make them private
size_t rows;
size_t cols;
map_type data;
public:
using key_type = std::array<size_t, 2>;
using mapped_type = T;
using map_type = std::map<key_type, mapped_type>;
Matrix(size_t r, size_t c) : rows(r), cols(c) { }
const T& operator [](key_type key) const { return data[key]; }
T& operator [](key_type key) { return data[key]; }
// other operations as appropriate
};
You have to provide members:
const T& operator [](std::pair<std::size_t, std::size_t>) const;
T& operator [](std::pair<std::size_t, std::size_t>);

Autoconverting template< T> to template<const T>

This piece below is supposed to be primarily for a string view with T={char, const char} being the primary intended template instantiation target.
The cmp function is supposed to compare the views analogously to strcmp.
The problem is that while char* happily converts to const char* I don't know how to get SVec<char> to convert to SVec<const char> just as happily.
The last line (cout<<(cmp(rv, rvc));) won't compile. I have to do the convertion explicitly (cmp(SVec<const char>(rv), rvc)). Can it be automatic like with char* to const char*?
The code (much simplified):
template <typename T>
class SVec {
protected:
T* begin_;
size_t size_;
public:
SVec(T* begin, size_t size) : begin_(begin), size_(size) {};
SVec(T* begin, T* end) : begin_(begin), size_(end-begin) {};
SVec(T* begin) : begin_(begin) { while (*(begin++)) {}; size_ = begin - 1 - begin_; }
//^null element indicates the end
///Conversion
operator SVec<const T>() const { return SVec<const T>(begin_, size_); }
};
//General lexicographic compare
template <typename T>
inline int cmp(const SVec<const T>& l, const SVec<const T> & r){
return 1;
}
//Char specialization
template <> inline int cmp<char>(const SVec<const char>& l, const SVec<const char>& r){
return 1;
}
//Explicit instantiation
template int cmp<char>(const SVec<const char>& l, const SVec<const char>& r);
#include <iostream>
int main(){
using namespace std;
char ar[] = "st";
SVec<char> sv = ar;
SVec<const char> svc = "str";
cout<<(cmp(SVec<const char>(sv), svc));
cout<<(cmp(sv, svc));
}
So the first thing you should probably do is make cmp a Koenig operator.
Then we can tag dispatch between the char and non-char versions:
template <typename T>
class SVec {
private:
static T* find_end(T* in) {
// I think while(*in)++in; would be better
// then the end is the null, not one-past-the-null.
while(*in++) {};
return in;
}
protected:
T* begin_ = nullptr;
size_t size_ = 0;
public:
SVec() = default;
SVec(SVec const&) = default;
SVec(T* begin, size_t size) : begin_(begin), size_(size) {};
SVec(T* begin, T* end) : SVec(begin, end-begin) {}
SVec(T* begin) : SVec(begin, find_end(begin)) {}
operator SVec<const T>() const { return SVec<const T>(begin_, size_); }
friend int cmp(SVec<T> l, SVec<T> r) {
return cmp_impl(l, r, std::is_same<std::decay_t<T>,char>{});
}
private:
static int cmp_impl(SVec<const char> l, SVec<const char> r, std::true_type){
return 1;
}
static int cmp_impl(SVec<const T> l, SVec<const T> r, std::false_type){
return 1;
}
};
std::decay_t and enable_if_t are C++14, but are just short versions of the typename spam _t-less versions.
Notice I take things by value instead of const& : a pointer and a size_t do not merit passing by reference.
I also forward all ctors into 2 bottlenecks.
...
The Koenig operator friend int cmp uses ADL to be found. It is not a template function, but rather a function that is generated for each template class instance, which is an important distinction.
Koenig operators avoid the problems of template operators, while allowing them to vary with the type of the template. Such an operator can only be found via ADL (argument dependent lookup).
It then dispatches to the _impl overloads (which are now const-correct) based on if T is a char or not at compile time.