I wrote a function to print a given vector.
template <typename T>
void print_vector(std::string text, std::vector<T> &vect){
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(T &t: vect){
std::cout << t << ", ";
}
std::cout << std::endl << "--------------------" << std::endl;
}
But when I give a vector of shared_ptr to the function, it prints the address, but not the pointed value.
Is there a way to print the value when the element is a shared_ptr..?
I tried the following way, but it gives me a compile error and I can't figure out how to fix it.
template <typename T, typename F>
void print_vector(std::string text, std::vector<T> &vect){
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(T &t: vect){
if(std::is_same<T, std::shared_ptr<F>>::value) {
std::cout << *t << ", ";
} else {
std::cout << t << ", ";
}
}
std::cout << std::endl << "--------------------" << std::endl;
}
Overload your function for vectors of smart pointers.
template <typename T>
void print_vector(std::string text, std::vector<T> &vect){
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(T &t: vect){
std::cout << t << ", ";
}
std::cout << std::endl << "--------------------" << std::endl;
}
template <typename T>
void print_vector(std::string text, std::vector<std::shared_ptr<T>> &vect){
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(auto &t: vect){
std::cout << *t << ", ";
}
std::cout << std::endl << "--------------------" << std::endl;
}
If you have more cases where you wish to print something different, you may find that some of the overloads are ambiguous, you may have to disable the ambiguous templates when they should match each other.
You can overload operator for shared_ptr check out the following code:
template<typename T>
ostream& operator<<(ostream& out, const shared_ptr<T>& s_ptr)
{
if (s_ptr != nullptr)
out << (*s_ptr);
return out;
}
template <typename T>
void print_vector(std::string text, std::vector<T> &vect){
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(T &t: vect){
std::cout << t << ", ";
}
std::cout << std::endl << "--------------------" << std::endl;
}
you want to overload the stream operator for shared_ptr, this could either be for a specific type or for all types:
template <typename T>
std::ostream& operator << (std::ostream& os, const std::shared_ptr< T >& p)
{
if ( p )
{
os << *p;
}
else
{
os << "<null>";
}
return os;
}
Just overload the function template:
template <typename T>
void print_vector(std::string text, std::vector<T> &vect){
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(T &t: vect){
std::cout << t << ", ";
}
std::cout << std::endl << "--------------------" << std::endl;
}
template <typename T>
void print_vector(std::string text, std::vector<std::shared_ptr<T>> &vect) {
std::cout << ">>>>>>>>>> " << text << " <<<<<<<<<<" << std::endl;
for(auto &t: vect){
std::cout << *t << ", ";
}
std::cout << std::endl << "--------------------" << std::endl;
}
Now it will handle both cases.
Related
Using the example for std::swap on cppreference I tried the following SWAP-template:
#include <algorithm>
#include <iostream>
namespace Ns
{
class A
{
int id{};
friend void swap(A& lhs, A& rhs)
{
std::cout << "swap(" << lhs << ", " << rhs << ")\n";
std::swap(lhs.id, rhs.id);
}
friend std::ostream& operator<< (std::ostream& os, A const& a)
{
return os << "A::id=" << a.id;
}
public:
A(int i) : id{i} { }
A(A const&) = delete;
A& operator = (A const&) = delete;
};
}
template<typename T> void SWAP(T &l, T &r)
{
try { std::swap(l, r); }
catch(...) { swap(l, r); }
}
int main()
{
std::cout << "\n======================\n";
int a = 5, b = 3;
std::cout << "before: " << a << ' ' << b << '\n';
std::swap(a,b);
std::cout << "after: " << a << ' ' << b << '\n';
std::cout << "\n=========\n";
Ns::A p{6}, q{9};
std::cout << "before: " << p << ' ' << q << '\n';
// std::swap(p, q); // error, type requirements are not satisfied
swap(p, q); // OK, ADL finds the appropriate friend `swap`
std::cout << "after: " << p << ' ' << q << '\n';
std::cout << "\n======================\n";
std::cout << "before: " << a << ' ' << b << '\n';
SWAP(a,b);
std::cout << "after: " << a << ' ' << b << '\n';
std::cout << "\n=========\n";
std::cout << "before: " << p << ' ' << q << '\n';
SWAP(p, q);
std::cout << "after: " << p << ' ' << q << '\n';
}
to handle the 'friend' swap-function in the namespace; to have just a single SWAP function to call that will handle all cases.
The compiler-error: swap was not declared in this scope
Why does calling swap() for the namespace work in main but not in the template?
and is there a way to have a generalized 'SWAP'-function to handle all such cases?
(edit)
Thanks to #rici the following change to the template works:
template<typename T> void SWAP(T &l, T &r)
{
using namespace std;
swap(l, r);
}
I would still appreciate an ELI5 for the first part of my question: what/how/why does this work ...
There are 2 problems.
Please first read the definition of 'std::swap' here.
You will read the requirements for the type.
You are using exceptions in your swap function. Remove that.
From the description, you can see that your type must be
Type requirements
T must meet the requirements of MoveAssignable and MoveConstructible.
T2 must meet the requirements of Swappable.
You defined (deleted) a constructor and assign operator. With that the compiler will not create the standard constructors/assign operators for you. Please read about the rule of 5.
Your class is no longer MoveAssignable and MoveConstructible.
Simply remove the deleted operator and constructor.
Like the below. Then it will compile.
#include <algorithm>
#include <iostream>
namespace Ns
{
class A
{
int id{};
friend void swap(A& lhs, A& rhs)
{
std::cout << "swap(" << lhs << ", " << rhs << ")\n";
std::swap(lhs.id, rhs.id);
}
friend std::ostream& operator<< (std::ostream& os, A const& a)
{
return os << "A::id=" << a.id;
}
public:
A(int i) : id{ i } { }
//A(A const&) = delete;
//A& operator = (A const&) = delete;
};
}
template<typename T>
void SWAP(T& l, T& r)
{
std::swap(l, r);
}
int main()
{
std::cout << "\n======================\n";
int a = 5, b = 3;
std::cout << "before: " << a << ' ' << b << '\n';
std::swap(a, b);
std::cout << "after: " << a << ' ' << b << '\n';
std::cout << "\n=========\n";
Ns::A p{ 6 }, q{ 9 };
std::cout << "before: " << p << ' ' << q << '\n';
// std::swap(p, q); // error, type requirements are not satisfied
swap(p, q); // OK, ADL finds the appropriate friend `swap`
std::cout << "after: " << p << ' ' << q << '\n';
std::cout << "\n======================\n";
std::cout << "before: " << a << ' ' << b << '\n';
SWAP(a, b);
std::cout << "after: " << a << ' ' << b << '\n';
std::cout << "\n=========\n";
std::cout << "before: " << p << ' ' << q << '\n';
SWAP(p, q);
std::cout << "after: " << p << ' ' << q << '\n';
}
I'm getting compiler error when using std::forward on a class template parameter, but not on a function template parameter. I'd like to know how to std::forward a class template parameter. This is my code:
#include <iostream>
#include <vector>
template<typename T>
class Data_List {
std::vector<T> data_list;
public:
Data_List() = default;
~Data_List() = default;
std::size_t get_list_size() {
return data_list.size();
}
void add_to_list(T&& data) {
std::cout << "\nbefore inside add_to_list: " << data.size() << std::endl;
data_list.push_back(std::forward<T>(data));
std::cout << "after inside add_to_list: " << data.size() << std::endl;
}
};
template<typename T>
void print(T&& t) {
}
int main() {
Data_List<std::vector<int>> list_of_data;
std::vector<int> data(100, 2);
std::cout << "\n1. before size: " << data.size() << std::endl;
std::cout << "1. before Data_List size: " << list_of_data.get_list_size() << std::endl;
print(data);
// list_of_data.add_to_list(data); // gives compiler error here
std::cout << "\n1. after size: " << data.size() << std::endl;
std::cout << "1. after Data_List size: " << list_of_data.get_list_size() << std::endl;
std::cout << "--------------------------------------------------------------------------\n" << std::endl;
std::cout << "\n2. before size: " << data.size() << std::endl;
std::cout << "2. before Data_List size: " << list_of_data.get_list_size() << std::endl;
print(std::move(data));
list_of_data.add_to_list(std::move(data));
std::cout << "\n2. after size: " << data.size() << std::endl;
std::cout << "2. after Data_List size: " << list_of_data.get_list_size() << std::endl;
std::cout << "--------------------------------------------------------------------------\n" << std::endl;
}
This is the error I'm getting cannot bind rvalue reference of type ‘std::vector<int>&&’ to lvalue of type ‘std::vector<int>’
In here:
void add_to_list(T&& data) {
std::cout << "\nbefore inside add_to_list: " << data.size() << std::endl;
data_list.push_back(std::forward<T>(data));
std::cout << "after inside add_to_list: " << data.size() << std::endl;
}
data isn't a forwarding reference, it's an rvalue reference, so you can't do something like list_of_data.add_to_list(data); because data is an lvalue.
To create a forwarding reference, the type must exist as a template parameter of the same function template (Give a reading to the forwarding references part of this cppreference.com page and look specifically at the first example):
function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template.
Basically, what you want to do is this:
// ...
template <typename U>
void add_to_list(U&& data) {
std::cout << "\nbefore inside add_to_list: " << data.size() << std::endl;
data_list.push_back(std::forward<U>(data));
std::cout << "after inside add_to_list: " << data.size() << std::endl;
}
// ...
Then data becomes a forwarding reference and does what is intended.
Demo
I wanted to write a template function for printing increasing and decreasing priority queues. Currently I have implemented it as
void print_queue1(priority_queue<int> q, string s){
cout << "Value of prior queue " << s << " is : [";
while(!q.empty()){
cout << " " << q.top() << ",";
q.pop();
}
cout << "]" << endl;
}
// min-heap
void print_queue2(priority_queue<int, vector<int>, greater<int>> q, string s){
cout << "Value of prior queue " << s << " is : [";
while(!q.empty()){
cout << " " << q.top() << ",";
q.pop();
}
cout << "]" << endl;
}
Is there some way to write a single template function that can do this?
You can use a variadic function template for this. Since the logic is the same regardless of the queue type, we can just accept any type of queue like
template <typename... Params>
void print_queue(priority_queue<Params...> q, string s){
cout << "Value of prior queue " << s << " is : [";
while(!q.empty()){
cout << " " << q.top() << ",";
q.pop();
}
cout << "]" << endl;
}
Here, Params will be deduced from the template parameters of the supplied priority_queue for you by the compiler and it will stamp out a concrete function for each different parameter set.
The template class std::priority_queue uses three template type parameters.
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
You may use those same three parameters in your function to accept any instantiation of std::priority_queue.
template<class T, class Container, class Compare>
void print_queue(priority_queue<T,Container,Compare> q, string s){
cout << "Value of prior queue " << s << " is : [";
while(!q.empty()){
cout << " " << q.top() << ",";
q.pop();
}
cout << "]" << endl;
}
Or, you may remove/restrict any one of them to enforce a subset of priority queues..
template<class Container, class Compare>
void print_queue(priority_queue<int,Container,Compare> q, string s){
// This function is really only designed for priority queues of int!
cout << "Value of prior queue " << s << " is : [";
while(!q.empty()){
cout << " " << q.top() << ",";
q.pop();
}
cout << "]" << endl;
}
I have class Date, functions bubbleSort, isAfter and printVector. So my task is: Use the function bubbleSort to sort vector type objects Date(using function isAfter which compares dates). I've done something but it doesn't works, so can anyone help me with this?
Function bubble sort(doesn't works with "Date", works fine with integers ,strings...).
Here is my code:
//isAfter
template<>
bool isAfter(const Date &first, const Date &second) {
if (first.getYear() == second.getYear()) {
if (first.getMonth() == second.getMonth()) {
if (first.getDay() == second.getDay()) {
cout << first.toString() << " is equal to " << second.toString() << endl;
return false;
} else if (first.getDay() > second.getDay()) {
cout << " " << first.toString() << " is after " << " " << second.toString() << endl;
return true;
} else if (first.getDay() < second.getDay()) {
cout << " " << second.toString() << " is after " << " " << first.toString() << endl;
return true;
}
} else if (first.getMonth() > second.getMonth()) {
cout << " " << first.toString() << " is after " << " " << second.toString() << endl;
return true;
} else if (first.getMonth() < second.getMonth()) {
cout << " " << second.toString() << " is after " << " " << first.toString() << endl;
return true;
}
} else if (first.getYear() > second.getYear()) {
cout << " " << first.toString() << " is after " << " " << second.toString() << endl;
return true;
} else if (first.getYear() < second.getYear()) {
cout << " " << second.toString() << " is after " << " " << first.toString() << endl;
return true;
}
return false;
}
//bubbleSort
template<typename T>
void bubbleSort(vector<T> &vec) {
bool swapp= true;
while (swapp) {
swapp= false;
for (unsigned int i = 0; i < vec.size()- 1; i++) {
if (vec[i] > vec[i + 1]) {
swap(vec[i], vec[i + 1]);
swapp = true;
}
}
}
}
so how can i add isAfter in bubbleSort to work fine with "Date" objects?
If this is always the sort order for dates and you control that type, you could implement the comparison operators operator<, operator>, operator<=, operator>=, operator== and operator!= for that type.
Otherwise, the conventional approach is to modify your sorting algorithm to accept a custom comparator (by convention, having the interface of operator<, which requires you to flip your comparison) from its callers, something like:
template <typename T, typename Compare>
void bubbleSort(vector<T> &vec, Compare compare) {
// as you currently have, but using compare(a, b) instead of a < b
}
template <typename T>
void bubbleSort(vector<T> &vec) {
bubbleSort(vec, std::less<>());
}
Then callers can use isAfter like this:
bubbleSort(dates, [](const Date& a, const Date& b) { return isAfter(b, a); });
I am learning about different stream state flags/functions in C++ such as good(), goodbit, bad(), badbit and so on. While testing with std::cin, I am unable to pass cin as an argument to a function (the compiler shows a lot of errors)
#include <iostream>
#include <sstream>
void print_state (const std::istream& stream) {
std::cout << " good()=" << stream.good();
std::cout << " eof()=" << stream.eof();
std::cout << " fail()=" << stream.fail();
std::cout << " bad()=" << stream.bad();
}
int main() {
std::cin.clear (std::ios::goodbit);
std::cout << "goodbit: " << print_state(std::cin) << std::endl;
std::cin.clear (std::ios::eofbit);
std::cout << "eofbit: " << print_state(std::cin) << std::endl;
std::cin.clear (std::ios::failbit);
std::cout << "failbit: " << print_state(std::cin) << std::endl;
std::cin.clear (std::ios::badbit);
std::cout << "badbit: " << print_state(std::cin) << std::endl;
return 0;
}
Desired output:
goodbit: good()=1 eof()=0 fail()=0 bad()=0
eofbit: good()=0 eof()=1 fail()=0 bad()=0
failbit: good()=0 eof()=0 fail()=1 bad()=0
badbit: good()=0 eof()=0 fail()=1 bad()=1
I know I can call the function directly with cin, such as std::cin.good(), but I want to know how can I pass cin as an argument to a function.
Edit:
I get a LOT of errors during compilation. An example:
F:\cpp_programming\stream_states.cpp: In function 'int main()':
F:\cpp_programming\stream_states.cpp:13:27: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'void')
std::cout << "goodbit: " << print_state(std::cin) << std::endl;
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
Since print_state does not return a value, it cannot be used with the insertion operator <<. The simplest way to correct this, is to call print_state on its own.
print_state(std::cin);
The corrected code is given below:
#include <iostream>
#include <sstream>
void print_state (const std::istream& stream) {
std::cout << " good()=" << stream.good();
std::cout << " eof()=" << stream.eof();
std::cout << " fail()=" << stream.fail();
std::cout << " bad()=" << stream.bad();
}
int main() {
std::cin.clear (std::ios::goodbit);
std::cout << "goodbit: "; print_state(std::cin); std::cout << std::endl;
std::cin.clear (std::ios::eofbit);
std::cout << "eofbit: "; print_state(std::cin); std::cout << std::endl;
std::cin.clear (std::ios::failbit);
std::cout << "failbit: "; print_state(std::cin); std::cout<< std::endl;
std::cin.clear (std::ios::badbit);
std::cout << "badbit: "; print_state(std::cin); std::cout << std::endl;
return 0;
}
To answer my own question
cin can be passed to a function as a function argument, such as:
functionName(std::cin);