Iterate throught n-dimensional vector c++ - c++

I wanted to write my own code to iterate over an n dimensional vector (where the dimension is known). Here is the code:
void printing(const auto& i, const int dimension){
int k= dimension;
for(const auto& j: i){
if(k>1){
cout<<"k: "<<k<<endl;
printing(j, --k);
}
else{
//start printing
cout<<setw(3);
cout<<j; //not quite sure about this line
}
cout<<'\n';
}
}
I get an error:
main.cpp:21:5: error: ‘begin’ was not declared in this scope
for(const auto& j: i){
^~~
Could someone help me to correct it or give me a better way to print the vector?
Thanks in advance for your time.

If the dimensions are known at compile-time, this can be solved easily with a template that takes dimensions as the non-type argument.
template <std::size_t Dimensions>
void printing(const auto& i){
if constexpr (Dimensions != 0) {
for(const auto& j: i){
// I'm not sure if it is intentional to print 'k' each iteration,
// but this is kept for consistency with the question
cout<<"k: " << Dimensions << endl;
printing<Dimensions - 1u>(j);
}
} else {
cout << setw(3);
cout << j;
cout << '\n';
}
}
The use would be, for a 2d vector:
printing<2>(vec);
Live Example
However, if you always know that const auto& i will be a std::vector type, you can potentially solve this even easier by just not using auto arguments at all, and instead use template matching:
// called only for the vector values
template <typename T>
void printing(const std::vector<T>& i){
for(const auto& j: i){
// possibly compute 'k' to print -- see below
printing(j);
}
}
// Only called for non-vector values
template <typename T>
void printing(const T& v) {
cout << setw(3);
cout << v;
cout << '\n';
}
Live Example
To compute the "dimension" of the vector, you can write a recursive type-trait for that:
#include <type_traits> // std::integral_constant
// Base case: return the count
template <std::size_t Count, typename T>
struct vector_dimension_impl
: std::integral_constant<std::size_t, Count> {};
// Recursive case: add 1 to the count, and check inner type
template <std::size_t Count, typename T, typename Allocator>
struct vector_dimension_impl<Count, std::vector<T,Allocator>>
: vector_dimension_impl<Count + 1u, T> {};
// Dispatcher
template <typename T>
struct vector_dimension : vector_dimension_impl<0u, T> {};
// Convenience access
template <typename T>
inline constexpr auto vector_dimension_v = vector_dimension<T>::value;
// Simple tests:
static_assert(vector_dimension_v<std::vector<int>> == 1u);
static_assert(vector_dimension_v<std::vector<std::vector<int>>> == 2u);
static_assert(vector_dimension_v<std::vector<std::vector<std::vector<int>>>> == 3u);
Live Example
With the above recursive trait, you can get the "dimension" of each templated vector type, without requiring the user to pass in the value at all.
If you still wanted to print k: each time, you can use the above simply with:
cout << "k: " << vector_dimension_v<T> << endl;
This only works if the type is known to be a vector -- but it could be written using concepts to work with anything following the abstract definition of something like a vector as well.
If you want this to work with any range-like type, then you could replace the vector-overload with a requires(std::ranges::range<T>) instead, and change the template-specializations for finding the dimension to also use the same. I won't pollute the answer with all this code since it's largely the same as above -- but I'll link to it in action below:
Live Example

I have made a function that can print any n-dimensional iterable container:
template<typename Object, typename Iterable>
void Print(
const Iterable& iterable,
const string& separatorDimensions = "\n",
const function<void(const Object&)>& funcPrintElem = [] (const Object& obj) {
static_assert(
is_arithmetic_v<Object> || is_same_v<remove_const_t<remove_pointer_t<Object>>, char>,
R"(The object from the innermost range is not a built-in/c-string type, please provide a valid print element function.)"
);
cout << obj << ' ';
}
) {
if constexpr (ranges::range<Iterable>) {
ranges::for_each(iterable, [&] (const auto& it) { Print(it, separatorDimensions, funcPrintElem); });
cout << separatorDimensions;
} else {
funcPrintElem(iterable);
}
}
The function has a default std::function that can print any built-in type like int, unsigned char, long long etc... and the c-string like char* or const char*, if you have another object like a pair or tuple or an object of your class you can pass a function that prints your object.
You can use the function like this: (you must explicitly tell the function your inner most object like below)
int main() {
cout << "v: " << endl;
vector<uint16_t> v { 1, 2, 3 };
Print<uint16_t>(v);
cout << endl << "ll: " << endl;
list<list<const char*>> ll { { "a", "b" }, { "c", "d" } };
Print<const char*>(ll);
struct smth {
int a;
char b;
};
cout << endl << "smths: " << endl;
vector<smth> smths { { 14, '0' }, { 18, '1' } };
Print<smth>(smths, "\n", [] (const smth& obj) { cout << "a = " << obj.a << ", b = " << obj.b << endl; });
return 0;
}
The function can be found here, maybe I will update in the future to support more things.
Edit: You need to have at least c++20 for this function to work

Related

Is there a way to loop inside an object to print the values of all its members in c++?

recently I was in an interview, and the last question in the interview was to make a function that takes an object as an argument. The function has to loop inside the passed object to print all of the values of its attributes.
something likefor/in in javascript
is there such thing in c++ ?
Actually, you can do this for some kinds of types.
For tuple-like types (see std::apply and fold expression):
template<typename T> void print(T&& tuple) {
apply([](auto&&... elements) { (..., (std::cout << elements << '\n')); }, tuple);
}
int main() { print(std::tuple{1, 2.3, "abc"}); }
For aggregate types if you know the number of their fields (see structured binding):
template<typename T> void print(T&& two_fields_aggregate) {
auto&& [a, b] = two_fields_aggregate;
std::cout << a << '\n' << b << '\n';
}
struct Example {
int i;
double d;
};
int main() { print(Example{1, 2.3}); }
The hardest case: aggregate types if you don't know the number of their fields (see Boost.MagicGet):
template<typename T> void print(T&& aggregate) {
apply(
[](auto&&... elements) { (..., (std::cout << elements << '\n')); },
boost::pfr::structure_to_tuple(aggregate)
);
}
struct Example {
int i;
double d;
std::string_view s;
};
int main() { print(Example{1, 2.3, "abc"}); }
If your object has private data, you obviously cannot access it from the outside, therefore cannot print it.

Outputting a Returned pair Without a Temporary

Let's say that I have a function: pair<int, int> foo() I want to directly output both elements of this without using a temporary.
Is there a way that I can output this, or maybe convert it into a string to output? Could I perhaps use tie to do this?
Here's what I'm trying to do with the temporary:
const auto temporary = foo();
cout << temporary.first << ' ' << temporary.second << endl;
In c++17 standard, you can use structured binding declaration
std::pair<int, int> get_pair()
{
return {10, 20};
}
int main()
{
auto [x, y] = get_pair();
std::cout << x << " " << y << std::endl;
return 0;
}
No. You can't write that function without using a non-temporary. If you really need to, you should probably change the structure of your code. Technically, you could also use a global variable (although I strongly do not recommend this). I don't think tie would work for what you want it for either.
You can create a small class that wraps the std::pair, and enable output streams to print it via operator<<:
template<typename PairT>
struct printable {
const PairT& p;
printable(const PairT& p)
: p{p}
{}
};
template<typename CharT, typename PairT>
std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& out, const printable<PairT>& pair) {
out << pair.p.first << ' ' << pair.p.second;
return out;
}
Then you can use it like this:
auto foo() {
return std::pair<int, int>(1, 2);
}
int main() {
std::cout << printable(foo());
}
Live example
Of course, you could also just enable the printing directly for an std::pair...
template<typename CharT, typename A, typename B>
std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& out, const std::pair<A, B>& pair) {
out << pair.first << ' ' << pair.second;
return out;
}
// (...)
std::cout << foo(); // And this would work just fine
... but I don't really recommend it, specially on a header, since you would be basically changing behavior of standard types and your colleagues (or yourself, in the future) may be confused by it.

Adding a template to a class, that's being used in a multiset

The fix for this is probably very simple, but I cannot find the answer. An answer will be rewarded with my thanks and my tears.
Basically the below code works just fine without the template (with the T's as primitives of course) but once I add the template, it says my argument list is missing. I figured this has to do with declaring , but these functions are not using scope resolution, at least not in a way I'm familiar with. How do I get this to work?
template<class T>
class Foo
{
public:
Foo(T s, int i) : Data(s), pri(i) {}
//Overload the relational operator so that the priority is compared.
bool operator < (const Foo<T>& n) const { return n.pri < pri; }
T getData() { return Data; }
int getId() { return pri; }
private:
T Data;
int pri;
};
This is main
int main(void)
{
set<Foo> s; //These should actually be multiset, but was trying to get it to
s.insert(Foo("C++", 9)); //work as a set before jumping to multiset
s.insert(Foo("Is ", 7));
s.insert(Foo("Fun ", 3));
set<Foo>::iterator p;
for (p = s.begin(); p != s.end(); p++)
{
Foo n = *p;
cout << "Id: " << n.getId() << "\t Data: " << n.getData() << endl;
}
return 0;
}
If you're curious, the program is supposed to take a string(or other type) along with a priority and sort the priority, the program isn't complete, but I'm supposed to use this Class in my program, but I'm tripped up over in converting it into a template.
std::set expect a type.
Before the introduction of the template part, Foo was a type.
Now that is a template class, Foo isn't a type anymore. Foo<int> is a type; Foo<std::string> is a type; not Foo.
So
std::set<Foo<int>> s;
can work,
std::set<Foo> s;
give an error.
When you declare class Foo {};, Foo is the name of a class. However, when you declare template <class T> class Foo {};, Foo is the name of a template. A template is not a class: it's a recipe for creating classes. Classes such as Foo<int> or Foo<char>.
It seems you want to store std::strings in your Foos in the set, which means the code should look like this:
int main(void)
{
set<Foo<string>> s; //These should actually be multiset, but was trying to get it to
s.insert(Foo<string>("C++", 9)); //work as a set before jumping to multiset
s.insert(Foo<string>("Is ", 7));
s.insert(Foo<string>("Fun ", 3));
set<Foo<string>>::iterator p;
for (p = s.begin(); p != s.end(); p++)
{
Foo<string> n = *p;
cout << "Id: " << n.getId() << "\t Data: " << n.getData() << endl;
}
return 0;
}

C++ Printing array to any output object (by function)

I'm trying to make a function, which can 'print' content of array to any output object. It's looking a little bit like this:
template <class T, class Z>
void print(T* array, int& size, Z& obj)
{
for (int k = 0; k < size; k++)
Z<< array[k] << " ";
Z<< std::endl;
}
I want obj to be any output object like std::cout or any of fstream, so I could call it using:
print(arr_name, arr_size, std::cout)
or
std::ostream file;
print(arr_name, arr_size, file)
Unfortunately, in my current verion it doesn't work at all (errors involve '<<' operator). What's wrong? Is it even possible to create such function?
You are not using the name of the argument but the type.
Z << array[k] << " ";
should be
obj << array[k] << " ";
In addition, passing the size as non-const reference doesn't make much sense as you'll need an l-value, const int& size would be better.
But this won't be so much generic in any case. The best solution would be to use iterators and skip plain C arrays totally, and use std::array as a replacement (which makes sense since you are working in C++):
template <class T, class Z>
void print(const T& data, Z& obj)
{
for (const typename T::value_type& element : data)
obj << element;
obj << std::endl;
}
std::array<int, 5> data = {1,2,3,4,5};
std::vector<std::string> data2;
print(data, std::cout);
print(data2, std::cout);

Variadic template function unpack order

I have this code:
template<typename ...T>
struct Test
{
void call(string str)
{
abc(get<T>(str)...);
}
template<typename U>
string get(string& inp)
{
string ret{ inp[0] };
inp.erase(0, 1);
cout << ret << endl; // first "a", next "b", next "c" - everything is ok
return ret;
}
void abc(string a, string b, string c)
{
cout << a << " " << b << " " << c << endl; // "b c a" - why?
}
};
I'm calling it like this:
Test<int, bool, float> test;
test.call("abc");
And the output is b c a thought I expect a b c. Moreover in get() function I have a correct order. Why is this? I can't find any rule about this order.
The order of evaluation of function arguments is unspecified.
abc(get<T>(str)...);
That is essentially the same as:
abc(get<T1>(str), get<T2>(str), get<TN>(str));
You could enforce evaluation order by generating an array to store the strings, then dispatching from that array:
template <std::size_t N, std::size_t... Idx>
void call_helper(std::array<std::string, N> arr, std::index_sequence<Idx...>) {
abc(std::get<Idx>(arr)...);
}
void call(string str)
{
std::array<std::string,sizeof...(T)> arr { get<T>(str)... };
call_helper(arr, std::index_sequence_for<T...>{});
}
The order of function call arguments are not guaranteed. Therefore, abc(get<T>(str)...); doesn't have a defined order.
See Order of evaluation in C++ function parameters for more details.