I am trying to write sorting template function to make it work with custom classes.
My code is:
#include <iostream>
#include <vector>
struct test
{
int value;
test(int a) : value(a){};
void print() { printf("the value is : %d", value); };
};
template <class T>
void bubblesort(T *m_data, size_t size, bool (*cmp)(const T &l, const T &r))
{
for (uint32_t i = 0; i < size; i++)
for (uint32_t j = 1; j < size - i; j++)
if (cmp(m_data[j - 1], m_data[j]))
{
T temp = m_data[j];
m_data[j] = m_data[j - 1];
m_data[j - 1] = temp;
}
}
int main()
{
std::vector<test> arr;
for (size_t i = 0; i < 10; i++)
arr.emplace_back(i);
std::vector<test *> arr1;
for (auto &i : arr)
arr1.emplace_back(&i);
bubblesort<test>(&arr[0], arr.size(), [](const test &l, const test &r) { return l.value < r.value; });
// bubblesort<test*>(&arr1[0], arr1.size(), [](const test *&l, const test *&r) { return l->value < r->value; });
for (auto i : arr)
printf("%d\n", i.value);
}
My question is how do you sort arr1 using the bubblesort function above? What kind of modification do I have to make in my code to be able to do so?
uncommenting the bubblesort line gives error
error: invalid user-defined conversion from 'main()::<lambda(const test*&, const test*&)>' to 'bool (*)(test* const&, test* const&)' [-fpermissive]
[build] 48 | bubblesort<test *>(&arr1[0], arr1.size(), [](const test *&l, const test *&r) { return l->value < r->value; });
Your function has the wrong type; T is test*, so you need test* const& - "reference to const pointer to test" - as the error message says.
(const test*& is "reference to pointer to const test.)
Your solution cannot work with templates...it cannot deduce the parameters type.
Consider modifying your code as follow:
struct test
{
int value;
explicit test(int a) : value(a) {};
void print() { printf("the value is : %d", value); };
};
template <class T, class _cmp>
void bubblesort(T *m_data, size_t size, _cmp cmp)
{
for (uint32_t i = 0; i < size; i++)
for (uint32_t j = 1; j < size - i; j++)
if (cmp(m_data[j - 1], m_data[j]))
{
T temp = m_data[j];
m_data[j] = m_data[j - 1];
m_data[j - 1] = temp;
}
}
int main()
{
std::vector<test> arr;
for (int i = 0; i < 10; i++)
arr.emplace_back(i);
std::vector<test *> arr1;
for (auto i : arr)
arr1.emplace_back(&i);
bubblesort<test>(&arr[0], arr.size(), [](const test &l, const test &r) -> bool { return l.value < r.value; });
bubblesort<test*>(&arr1[0], arr1.size(), [](const test* l, const test* r) -> bool { return l->value < r->value; });
for (auto i : arr)
printf("%d\n", i.value);
}
Related
I wrote an expression template to sum up to three vectors together. However, as you can see in my code, this doesn't scale very well because for every additional sum operand I have to add another nested template expression. Is there a way to refactor this code to handle a (theoretically) infinite amount of additions?
template<class A>
struct Expr {
operator const A&() const {
return *static_cast<const A*>(this);
}
};
template<class A, class B>
class Add : public Expr<Add<A,B>> {
private:
const A &a_;
const B &b_;
public:
Add(const A &a, const B &b) : a_(a), b_(b) { }
double operator[] (int i) const {
return a_[i] + b_[i];
}
};
class Vector : public Expr<Vector> {
private:
double *data_;
int n_;
public:
Vector(int n, double w = 0.0) : n_(n) {
data_ = new double[n];
for(int i = 0; i < n; ++i) {
data_[i] = w;
}
}
double operator[] (int i) const {
return data_[i];
}
friend Expr<Add<Vector, Vector>> operator+(Vector &a, Vector &b) {
return Add<Vector, Vector>(a, b);
}
friend Expr<Add<Add<Vector, Vector>, Vector>> operator+(const Add<Vector, Vector> &add, const Vector &b) {
return Add<Add<Vector, Vector>, Vector>(add, b);
}
template<class A>
void operator= (const Expr<A> &a) {
const A &a_(a);
for(int i = 0; i < n_; ++i) {
data_[i] = a_[i];
}
}
};
int main() {
constexpr int size = 5;
Vector a(size, 1.0), b(size, 2.0), c(size);
c = a + b + a;
return 0;
}
This was working for me:
class Vector : public Expr<Vector> {
private:
double *data_;
int n_;
public:
Vector(int n, double w = 0.0) : n_(n) {
data_ = new double[n];
for(int i = 0; i < n; ++i) {
data_[i] = w;
}
}
double operator[] (int i) const {
return data_[i];
}
template<class A, class B>
friend Add<A, B> operator+(const Expr<A> &a, const Expr<B> &b) {
return Add<A, B>(a, b);
}
template<class A>
void operator= (const Expr<A> &a) {
const A &a_(a);
for(int i = 0; i < n_; ++i) {
data_[i] = a_[i];
}
}
};
I'm no template wizard (and I'm not up-to-date with the latest possibilities), but you can at least make a function that added a variadic amount of vectors, using something like described in the code below.
You could then buildup you expressiontree like you did before and call this function in you evaluation (operator=) function.
edit: updated the code, based on this solution (credits there)
#include <vector>
#include <algorithm>
template<typename T>
using Vec = std::vector<T>;
template<typename T, typename...Args>
auto AddVector_impl(Vec<Args> const & ... vecs){
auto its = std::tuple(cbegin(vecs)...);
auto add_inc = [](auto&... iters){
return ((*iters++) + ... );
};
auto end_check = [&](auto&...iters){
return ((iters != cend(vecs)) && ...);
};
Vec<T> res;
for(auto it = back_inserter(res); apply(end_check,its);){
*it++ = apply(add_inc,its);
}
return res;
}
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
return AddVector_impl<T>(vt,vargs...);
}
#include <iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
outputs:
4 4 4 4 4
I like to think I have grasped most aspects of object oriented programming but C++ has yet again presented me with an unexpected result. While creating a static array class in C++ (much like std::array), I added the + operator and it gave me a very strange compiler error.
Has anyone encountered this situation before?
#pragma once
#ifdef NDEBUG
#define __ESL_Array_AssertCorrectInitSize(array, init)
#else
#define __ESL_Array_AssertCorrectInitSize(array, init) if (init.size() != array->Size()) throw ESL::ArrayInitializationException("std::initializer_list size is different than static size");
#endif // NDEBUG
#include<cstdint>
#include<utility>
#include<stdexcept>
namespace ESL
{
class ArrayInitializationException : public std::runtime_error
{
public:
ArrayInitializationException(const std::string &msg): std::runtime_error(msg) {}
};
template <typename T, uint32_t S>
class Array
{
public:
Array(): m_data() {}
Array(const T (&arr)[S]):
m_data()
{
const T *src_itr = arr;
T *dst_itr = m_data;
for (uint32_t i = 0; i < S; ++i)
*(dst_itr++) = *(src_itr++);
}
Array(std::initializer_list<T> list):
m_data()
{
__ESL_Array_AssertCorrectInitSize(this, list)
const T *src_itr = list.begin();
T *dst_src = m_data;
for (uint32_t i = 0; i < S; ++i)
{
*(dst_src++) = *(src_itr++);
}
}
Array(const Array &a):
m_data()
{
const T *src_itr = a.m_data;
T *dst_itr = m_data;
for (uint32_t i = 0; i < S; ++i)
*(dst_itr++) = *(src_itr++);
}
Array(Array &&a):
m_data()
{
T *src_itr = a.m_data;
T *dst_itr = m_data;
for (uint32_t i = 0; i < S; ++i)
*(dst_itr++) = std::forward<T>(*(src_itr++));
}
Array &operator=(const Array &a)
{
const T *src_itr = a.m_data;
T *dst_itr = m_data;
for (uint32_t i = 0; i < S; ++i)
*(dst_itr++) = *(src_itr++);
return *this;
}
Array &operator=(Array &&a)
{
const T *src_itr = a.m_data;
T *dst_itr = m_data;
for (uint32_t i = 0; i < S; ++i)
*(dst_itr++) = std::forward<T>(*(src_itr++));
return *this;
}
constexpr uint32_t Size() const { return S; }
const T &operator[](uint32_t index) const { return m_data[index]; }
T &operator[](uint32_t index) { return m_data[index]; }
const T *begin() const { return m_data; }
T *begin() { return m_data; }
const T *end() const { return m_data + S; }
T *end() { return m_data + S; }
bool operator==(const Array &a) const
{
const T *itr1 = m_data;
const T *itr2 = a.m_data;
for (uint32_t i = 0; i < S; ++i)
{
if (*(itr1++) != *(itr2++)) return false;
}
return true;
}
bool operator!=(const Array &a) const
{
const T *itr1 = m_data;
const T *itr2 = a.m_data;
for (uint32_t i = 0; i < S; ++i)
{
if (*(itr1++) != *(itr2++)) return true;
}
return false;
}
template <uint32_t S2>
Array<T, S + S2> operator+(const Array<T, S2> &a) const
{
Array<T, S + S2> res;
const T *src_itr = m_data;
T *dst_itr = res.m_data;
for (uint32_t i = 0; i < S; ++i)
*(dst_itr++) = *(src_itr++);
src_itr = a.m_data;
for (uint32_t i = 0; i < S2; ++i)
*(dst_itr++) = *(src_itr++);
return res;
}
private:
T m_data[S];
};
}
If you need any more code, I'd be willing to post the entire file. I appreciate any input! Thanks!
EDIT: Just realized I forgot the compiler output:
In instantiation of ‘ESL::Array<T, (S + S2)> ESL::Array<T, S>::operator+(const ESL::Array<T, S2>&) const [with unsigned int S2 = 2; T = double; unsigned int S = 3]’:
[build] /home/joshlengel/Dev/C++/ESL/Main.cpp:10:20: required from here
[build] /home/joshlengel/Dev/C++/ESL/ESL/include/collection/Array.h:135:30: error: ‘double ESL::Array<double, 5>::m_data [5]’ is private within this context
[build] 135 | T *dst_itr = res.m_data;
[build] | ~~~~^~~~~~
[build] /home/joshlengel/Dev/C++/ESL/ESL/include/collection/Array.h:149:11: note: declared private here
[build] 149 | T m_data[S];
The reason is for the class, Array<double, 2> and Array<double, 3> are completely two different classes. This is why it says that you cant access private members. For this you either have to make the m_data member public, or use begin() like so,
template <uint32_t S2>
Array<T, S + S2> operator+(const Array<T, S2>& a) const
{
Array<T, S + S2> res;
// You can ditch the for loops and use std::copy instead. It *can* be more efficient.
std::copy(begin(), end(), res.begin());
std::copy(a.begin(), a.end(), res.begin() + S);
return res;
}
I want to use structure Item as key in unordered_map
I implemented structures for hash and equal operations.
But I have an error
hashtable_policy.h:1384:16: error: no match for call to '(const ItemHash) (const Item&)'
solution.cpp:28:12: note: candidate: 'size_t ItemHash::operator()(Item)'
32 | size_t operator()(Item item) {
solution.cpp:28:12: note: passing 'const ItemHash*' as 'this' argument discards qualifiers
How can I fix the error?
My code
vector<int> get_key(const string& s) {
vector<int> res(26, 0);
for (int i = 0; i < s.size(); ++i) {
int pos = s[i] - 'a';
res[pos]++;
}
return res;
}
struct Item {
vector<int> v;
Item(const vector<int>& vec) : v(vec) {}
bool operator==(Item other) {
if (v.size() != other.v.size()) {
return false;
}
for (int i = 0; i < v.size(); ++i) {
if (v[i] != other.v[i]) {
return false;
}
}
return true;
}
};
struct ItemHash {
size_t operator()(Item item) {
auto vec = item.v;
size_t seed = vec.size();
for(auto& i : vec) {
seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
struct ItemEqual {
bool operator()(Item item1, Item item2) {
return item1 == item2;
}
};
vector<vector<int> > Solution::anagrams(const vector<string> &A) {
vector<vector<int>> res;
unordered_map<Item, vector<int>, ItemHash, ItemEqual> hash; // hash_key, vector of indexes
for (int i = 0; i < A.size(); ++i) {
Item item = Item(get_key(A[i]));
hash[item].push_back(i);
}
for (const auto& i : hash) {
res.push_back(i.second);
}
return res;
}
You need to const-qualify ItemHash::operator()(Item), i.e.,
struct ItemHash {
size_t operator()(Item item) const
// ^^^^ here
{
// as before...
}
Note that as #JeJo pointed out in the comments, you need the same fix for ItemEqual.
I'm new to C++. I was trying a leetcode question (436. Find Right Interval). Thought of complicating it by writing my own lower_bound just for my knowledge. But the below code is showing me runtime error: reference binding to null pointer of type 'value_type' (stl_vector.h). I'm unable to understand what's the issue, would someone please clarify what I'm doing wrong.
class Solution {
public:
vector<int> findRightInterval(vector<Interval>& intervals) {
int n = intervals.size();
vector<int> res;
vector<pair<Interval, int>> s_i;
for(int i = 0; i<n; i++) {
s_i.push_back(make_pair(intervals[i], i));
}
sort(s_i.begin(), s_i.end(), [](const pair<Interval, int>& a, const pair<Interval, int> &b) -> bool {
return a.first.start < b.first.start;
});
for(auto x : s_i) {
cout<<"["<<x.first.start<<","<<x.first.end<<"],"<<x.second<<endl;
}
for(int i = 0; i<n; i++) {
int val = intervals[i].end;
cout<<val<<endl;
//pair<Interval, int> temp = make_pair(Interval(val, val), 0);
auto it = lower_bound(s_i.begin(), s_i.end(), val,
[](const pair<Interval, int> &a, int val) -> bool {
return a.first.start < val;
});
if (it != s_i.end()) {
res[i] = it->second;
} else {
res[i] = -1;
}
}
return res;
}
};
Is there a nicer way to generate a list of points like than this? Libraries wise I'm open to any Eigen based method.
auto it = voxels.begin();
for(auto i = -180; i < 90; i++) {
for(auto j = -80; j < 70; j++) {
for(auto k = 20; k < 460; k++) {
*it = (Point3(i,j,k));
it++;
}
}
}
There's an immediate way to improve performance, by reserving enough space in the vector before you fill it with values.
There are many 'nicer' ways of doing it depending on what you think is nice.
Here's one way:
std::vector<Point3> populate()
{
// (arguable) maintainability benefit
constexpr auto I = axis_limits(-180, 90);
constexpr auto J = axis_limits(-80, 70);
constexpr auto K = axis_limits(20, 460);
// pre-reserve the space
std::vector<Point3> voxels;
voxels.reserve(volume(I, J, K));
// although it looks like it might be more work for the compiler, it gets optimised
// there is no loss of performance
for(i : I)
for(j : J)
for(k : J)
voxels.emplace_back(i, j, k);
return voxels;
}
Which will rely on the following infrastructure code:
struct Point3 {
Point3(int, int, int) {}
};
struct int_generator {
int_generator(int v)
: _v(v)
{}
int operator*() const {
return _v;
}
int_generator& operator++() {
++_v;
return *this;
}
bool operator!=(const int_generator& rhs) const {
return _v != rhs._v;
}
private:
int _v;
};
struct axis_limits : std::tuple<int, int>
{
using std::tuple<int, int>::tuple;
int_generator begin() const {
return std::get<0>(*this);
}
int_generator end() const {
return std::get<1>(*this);
}
};
constexpr int lower(const axis_limits& t)
{
return std::get<0>(t);
}
constexpr int upper(const axis_limits& t)
{
return std::get<1>(t);
}
int_generator begin(const axis_limits& t)
{
return std::get<0>(t);
}
int_generator end(const axis_limits& t)
{
return std::get<1>(t);
}
constexpr int volume(const axis_limits& x, const axis_limits& y, const axis_limits& z)
{
return (upper(x) - lower(x))
* (upper(y) - lower(y))
* (upper(z) - lower(z));
}