Create inline multidimensional arrays in C++ - c++

I have the following program, which I'd like to change to declare the multidimensional array inline:
int main() {
int x[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
for (const auto& [y, z] : x) {
std::cout << y << ", " << z << std::endl;
}
}
Is there a way to create inline arrays? Something like this:
for (const auto& [y, z] : <magic>{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}) {
std::cout << y << ", " << z << std::endl;
}

Not a very nice way, here is a possibility though:
for (const auto& [y, z] : std::array<std::pair<int, int>, 4>{{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}}) {
std::cout << y << ", " << z << std::endl;
}
One dimensional arrays like can be done using template type deduction with more modern versions of c++, which is a bit cleaner:
for (const auto& x : std::array{0, 1, 2}) {
std::cout << x << std::endl;
}
Introducing pairs makes it a fair bit messier though since the deduction doesn't work as nicely as you'd hope.

you can try a wrapper of C-style array to make it:
template<typename T>
struct xarray{
T data;
auto begin(){
using std::begin;
return begin(data);
}
auto end(){
using std::end;
return end(data);
}
};
template<typename T, typename... Y>
xarray(T, Y...) -> xarray<T[sizeof...(Y) + 1]>;
template<typename T, size_t X>
xarray(T (&&)[X]) -> xarray<T[X]>;
template<typename T, size_t X, size_t Y>
xarray(T (&&)[X][Y]) -> xarray<T[X][Y]>;
// ...
int main(){
for (auto&& [x, y] : xarray{{ {0, 1}, {0, 2} }}){ // additional {} is needed.
std::cout << x << " " << y << std::endl;
}
}
it's exactly equal to your code by C-style array.

Related

std::ranges algorithm function object customisation points AKA niebloids - problems with std lib types

All done with gcc 11.2 and libstdc++-11
Below code shows a variety of ways of using std::sort and then std::ranges::sort to sort builtins, user defined types and a std library type.
Only the std library type gives me trouble:
I can't easily define a custom operator< or operator<=> because it is UB to add that to namespace std. I think there is no way around this? (without using a lambda or similar)
for some reason I cannot pass a public member function as the proj parameter on the std lib type (but it works on the user defined type). Why? I was unable to penetrate the "wall of errors" enough to find out. gcc basically says: no known conversion for argument 3 from ‘<unresolved overloaded function type>’ to ‘std::identity’..
Update: My only theory on 2. above is that "unresolved overloaded function type" means that std::complex<double>::real has 2 overloads. One which takes a parameter (the "setter") and one which doesn't (the "getter"). Is there a syntax which allows me to specify that I want the "address of" the one without a parameter?
Update2: Thanks to 康桓瑋 for pointing out in the comments that taking the address of a member function in std is just UB anyway. However if I add a sum(int c) overload to thing (now added below) I get the same "unresolved overloaded" error. So the question remains, how can I select the one with no params. Or is there no way?
#include <algorithm>
#include <compare>
#include <complex>
#include <iostream>
#include <ranges>
#include <vector>
namespace std {
// this is UNDEFINED BEHAVIOUR!!! --- but "it works", so we know this option is what would be
// required, but is not available to us
std::partial_ordering operator<=>(const std::complex<double>& a, const std::complex<double>& b) {
return std::abs(a) <=> std::abs(b);
}
} // namespace std
// a user defined type
struct thing {
int x{};
int y{};
[[nodiscard]] int sum() const { return x + y; }
[[nodiscard]] int sum(int c) const { return x + y + c; } // added for update 2
friend std::strong_ordering operator<=>(const thing& a, const thing& b) {
return a.x + a.y <=> b.x + b.y;
}
friend bool operator==(const thing& a, const thing& b) { return a.x + a.y == b.x + b.y; }
friend std::ostream& operator<<(std::ostream& os, const thing& rhs) {
return os << "[" << rhs.x << "," << rhs.y << "]";
}
};
int main() {
// builtin types
auto ints = std::vector<int>{9, 10, 7, 8, 5, 6, 3, 4, 1, 2};
std::ranges::sort(ints);
std::ranges::sort(ints, {}, [](const auto& c) { return -c; });
for (const auto& e: ints) std::cout << e << " ";
std::cout << "\n";
auto things = std::vector<thing>{{9, 10}, {7, 8}, {3, 4}, {1, 2}, {5, 6}};
std::sort(things.begin(), things.end());
std::ranges::sort(things);
std::ranges::sort(things, {}, [](const auto& e) { return e.sum(); });
std::ranges::sort(things, [](const auto& a, const auto& b) { return a < b; }, {});
std::ranges::sort(things, {}, &thing::x);
std::ranges::sort(things, {}, &thing::sum); // COMPILE ERROR afte r update 2
for (const auto& e: things) std::cout << e << " ";
std::cout << "\n";
auto complexes = std::vector<std::complex<double>>{{9, 10}, {7, 8}, {3, 4}, {1, 2}, {5, 6}};
std::sort(complexes.begin(), complexes.end()); // requires operator< or <=> which is UB
std::ranges::sort(complexes); // requires operator<=> which is UB
std::ranges::sort(complexes, {}, [](const auto& c) { return std::abs(c); });
std::ranges::sort(complexes, {}, &std::complex<double>::real); // COMPILE ERROR!!
for (const auto& e: complexes) std::cout << e << " ";
std::cout << "\n";
return EXIT_SUCCESS;
}
You need to specify a comparison for T if std::less<T> is unavailable.
Both std::sort and std::ranges::sort require a strict weak ordering predicate, not operator<=> (but that can supply one, via < and std::less)
template<typename T>
bool complex_less (std::complex<T> lhs, std::complex<T> rhs) { return abs(lhs) < abs(rhs); };
int main() {
auto things = std::vector<thing>{{9, 10}, {7, 8}, {3, 4}, {1, 2}, {5, 6}};
std::sort(things.begin(), things.end());
std::ranges::sort(things);
std::ranges::sort(things, {}, [](const auto& e) { return e.sum(); });
std::ranges::sort(things, [](const auto& a, const auto& b) { return a < b; }, {});
std::ranges::sort(things, {}, &thing::x);
std::ranges::sort(things, {}, static_cast<int (thing::*)()>(&thing::sum)); // need cast to disambiguate pointer-to-member
for (const auto& e: things) std::cout << e << " ";
std::cout << "\n";
auto complexes = std::vector<std::complex<double>>{{9, 10}, {7, 8}, {3, 4}, {1, 2}, {5, 6}};
std::sort(complexes.begin(), complexes.end(), complex_less<double>); // fine
std::ranges::sort(complexes, complex_less<double>); // also fine
std::ranges::sort(complexes, {}, [](const auto& c) { return std::abs(c); }); // still fine
std::ranges::sort(complexes, {}, [](const auto& c) { return c.real(); }); // fine
for (const auto& e: complexes) std::cout << e << " ";
std::cout << "\n";
return EXIT_SUCCESS;
}

Initialize multiple dimension array

How can I initialize array with variables like int x[row][col];
int myArray[7][4] = { {1,2,3,4}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8}, {5,6,7,8} };
i want to initialize array as this =
int myarray({2,3,4},{12,4,5},{2,2,2})
The exact answer is you cannot initialize an array like that, i.e., without providing both row and col at compile time, though std::vector can do the job for you.
You can use some code like this:
#include <iostream>
#include <vector>
void print_vector(std::vector<int> &v) {
std::cout << "{ ";
for (auto &&i : v) {
std::cout << i;
if (&i != &v.back()) {
std::cout << ",";
}
}
std::cout << " }";
}
void print_matrix(std::vector<std::vector<int>> &v) {
std::cout << "{ ";
for (auto &&i : v) {
print_vector(i);
if (&i != &v.back()) {
std::cout << ", ";
}
}
std::cout << " }" << std::endl;
}
int main() {
std::vector<std::vector<int>> v = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
// same as std::vector<std::vector<int>> v({{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}});
print_matrix(v);
// prints { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 } } on stdout
}
I have included print_vector and print_matrix since the OP asked about them in the comments, though without thinking much about them. You can get better implementations on this thread.

Is there any shortcut method to print 2D-array c++

Is there any shortcut method in c++ to output 2d array(i.e. apart from for loop)?
Is there a special function in STL to output it.
Well, since you mentioned STL functions, you could use the std::for_each function with lambda functions to print the 2D array:
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
int matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
auto elem_printer = [](int num) { std::cout << num << " "; };
auto row_printer = [&elem_printer](int (&row)[3]) {
std::for_each(std::begin(row),std::end(row),elem_printer);
std::cout << std::endl;
};
std::for_each(std::begin(matrix),std::end(matrix),row_printer);
}
However, this is exactly the same as two for loops, but uglier.
I have this template for streams, which hides away some of the ugliness, and you benefit from it being reusable and it handles multiple dimensions. There is no way to get away without doing the loops somewhere, of course:
template <class Stream, size_t depth>
class Pretty
{
Stream& s;
public:
Pretty(Stream& s): s(s) {}
template <size_t d1, typename T>
Stream& operator <<( T const (&v)[d1])const
{
const char* sep = "{";
for (auto& m : v)
{
s << sep << m;
sep = ", ";
}
s << "}";
return s;
}
template <size_t d1, typename T, size_t d2>
std::ostream& operator <<(T const (&v)[d1][d2])const
{
enum {DENT = 4};
std::string dent (DENT,' ');
std::string indent(depth*DENT,' ');
std::string sep = "{\n" + indent + dent;
for (auto& m : v)
{
s << sep; Pretty<Stream,depth+1>(s) << m;
sep = ",\n" + indent + dent;
}
s << "\n" << indent << "}";
return s;
}
};
class PrettyNext
{};
Pretty<std::ostream,0> operator << (std::ostream& s, const PrettyNext&)
{
return Pretty<std::ostream,0>(s);
}
And usage:
int i [][3][2] = { { {1,2}, {3,4}, {5,6} },{{0}}};
std::cout << "This is a test:\n" << PrettyNext() << i << std::endl;
Output is:
This is a test:
{
{
{1, 2},
{3, 4},
{5, 6}
},
{
{0, 0},
{0, 0},
{0, 0}
}
}
I have been fighting to get this to work directly on std::ostream, but there is a collision with the standard char* handling I can't quite resolve.

C++ STL alogrithm like 'comm' utility

Can someone point me, please, if where is some algorithms within STL to compute difference and intersection per one call in manner of unix comm utility?
int main()
{
//For example we have two sets on input
std::set<int>a = { 1 2 3 4 5 };
std::set<int>b = { 3 4 5 6 7 };
std::call_some_func(a, b, ... );
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
}
My current implementation uses 2 calls of 'std::set_difference' and one call of 'std::set_intersection'.
I think this is probably a reasonably efficient implementation:
Features:
a) operates in linear time.
b) works with all ordered container types for input and all iterator types for output.
c) only requires operator< to be defined on the contained type, as per stl algorithms on sorted ranges.
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
example:
#include <tuple>
#include <set>
#include <vector>
#include <unordered_set>
#include <iterator>
#include <iostream>
/// #pre l and r are ordered
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
int main()
{
//For example we have two sets on input
std::set<int>a = { 1, 2, 3, 4, 5 };
std::set<int>b = { 3, 4, 5, 6, 7 };
std::vector<int> left;
std::set<int> right;
std::unordered_set<int> both;
comm(begin(a), end(a),
begin(b), end(b),
back_inserter(left),
inserter(both, both.end()),
inserter(right, right.end()));
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
std::copy(begin(left), end(left), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(both), end(both), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(right), end(right), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
example output (note that the 'both' target is an unordered set):
1, 2,
5, 3, 4,
6, 7,
There is no single function to do that, you'd have to call the three functions you mentioned, or write something yourself. That being said, here's my attempt, though I'm not sure it's going to be any faster than the three step method you've already described
#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
template <typename T>
void partition_sets(std::set<T> const& a,
std::set<T> const& b,
std::set<T>& difference_a,
std::set<T>& difference_b,
std::set<T>& intersection)
{
std::set_intersection(begin(a), end(a),
begin(b), end(b),
std::inserter(intersection, intersection.begin()));
std::copy_if(begin(a), end(a), std::inserter(difference_a, difference_a.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
std::copy_if(begin(b), end(b), std::inserter(difference_b, difference_b.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
}
Running your example
int main()
{
//For example we have two sets on input
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
std::set<int> x1;
std::set<int> x2;
std::set<int> x3;
partition_sets(a, b, x1, x2, x3);
std::cout << "a - b\n\t";
for (int i : x1)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "b - a\n\t";
for (int i : x2)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "intersection\n\t";
for (int i : x3)
{
std::cout << i << " ";
}
}
produces the output
a - b
1 2
b - a
6 7
intersection
3 4 5
Just write a wrapper for the three calls of the algorithms.
For example
#include <iostream>
#include<tuple>
#include <set>
#include <iterator>
#include <algorithm>
template <class T>
auto comm(const std::set<T> &first, const std::set<T> &second)
{
std::tuple<std::set<T>, std::set<T>, std::set<T>> t;
std::set_difference(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<0>(t), std::get<0>(t).begin()));
std::set_intersection(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<1>(t), std::get<1>(t).begin()));
std::set_difference(second.begin(), second.end(),
first.begin(), first.end(),
std::inserter(std::get<2>(t), std::get<2>(t).begin()));
return t;
}
int main()
{
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
auto t = comm(a, b);
for (auto x : std::get<0>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<1>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<2>(t)) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The program output is
1 2
3 4 5
6 7

no matching function for call to ‘begin(int**&)’

I wrote a c++ program as fllow(3.43.cpp):
#include <iostream>
using std::cout;
using std::endl;
void version_1(int **arr) {
for (const int (&p)[4] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << endl;
}
}
int main() {
int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
version_1(arr);
return 0;
}
Then I compile it by using: gcc my.cpp -std=c++11, there is an error I can not deal with.
Info:
3.43.cpp:6:30: error: no matching function for call to ‘begin(int**&)’
for (const int (&p)[4] : arr) {
^
3.43.cpp:6:30: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:42:0,
from /usr/include/c++/4.8.2/string:52,
from /usr/include/c++/4.8.2/bits/locale_classes.h:40,
from /usr/include/c++/4.8.2/bits/ios_base.h:41,
from /usr/include/c++/4.8.2/ios:42,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from 3.43.cpp:1:
/usr/include/c++/4.8.2/initializer_list:89:5: note: template<class _Tp> constexpr const _Tp* std::begin(std::initializer_list<_Tp>)
begin(initializer_list<_Tp> __ils) noexcept
I search it in google, but not find similar answer.
Since arr is just a pointer, there's no way to deduce how big it is. But, since you are actually passing in a real array, you can just template your function on its dimensions so you take the actual array by reference rather than having it decay to a pointer:
template <size_t X, size_t Y>
void foo(const int (&arr)[X][Y])
{
std::cout << "Dimensions are: " << X << "x" << Y << std::endl;
for (const int (&row)[Y] : arr) {
for (int val : row) {
std::cout << val << ' ';
}
std::cout << std::endl;
}
}
int main() {
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
foo(arr);
}
std::begin() and std::end() won't work for pointers. They only work for arrays. If you want to deduce the size of your array you'll need to pass it as a reference your function:
#include <cstddef>
template <std::size_t A, std::size_t B>
void version_1(int (&arr)[B][A]) {
for (const int (&p)[A] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << '\n';
}
}
Pointers are not the same as arrays. To be able to use range based for, your container must support std::begin and std::end. Standard C arrays can be used, but not pointers.