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
Related
I have following test example:
#include <iostream>
#include <vector>
void foo (std::vector<int> value) {
std::cout << "value "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
void foo2 (std::vector<int>&& rvalure_ref) {
std::cout << "rvalue_ref "
<< &rvalure_ref
<< " "
<< rvalure_ref.data()
<< " "
<< rvalure_ref.size()
<< std::endl;
}
int main() {
std::vector<int> value(5, 0);
std::cout << "init "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
foo(std::move(value));
std::cout << "done "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
The result of the code above is:
init 0x7ffed27c6450 0x56480bc1eeb0 5
value 0x7ffed27c6470 0x56480bc1eeb0 5
done 0x7ffed27c6450 0 0
Looks great:
Now, move to:
#include <iostream>
#include <vector>
void foo (std::vector<int> value) {
std::cout << "value "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
void foo2 (std::vector<int>&& rvalure_ref) {
std::cout << "rvalue_ref "
<< &rvalure_ref
<< " "
<< rvalure_ref.data()
<< " "
<< rvalure_ref.size()
<< std::endl;
}
int main() {
std::vector<int> value(5, 0);
std::cout << "init "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
foo2(std::move(value));
std::cout << "done "
<< &value
<< " "
<< value.data()
<< " "
<< value.size()
<< std::endl;
}
The result is:
init 0x7ffccc93a5c0 0x56124b3a8eb0 5
rvalue_ref 0x7ffccc93a5c0 0x56124b3a8eb0 5
done 0x7ffccc93a5c0 0x56124b3a8eb0 5
My problem is:
For the 1st case, it is perfectly called by "move semantics", and as you see, the ownership of the vector has been transfered to the function parameter. Finally, at "done", the data is null to verify the the vector at main() no longer owns the vector.
Now to explicitly claim the parameter is "rvalue reference", as case 2. As you see, actually it is like "call by (l)reference".
How can I figure out it?
In C++ parlance, is there a name for a type of class that does not inherit from any other class, has no virtual member functions, and is used as-is?
No there is no term for a type that does not inherit from any other class and has no virtual member functions.
One reason that such classification isnt that useful is that private inheritance is an implementation detail. (Maybe you are refering to public inheritance only?)
The type_traits library has lots of traits to query the category of a given type. See the below example:
#include <type_traits>
#include <iostream>
struct Foo {};
int main() {
std::cout << std::is_trivial<Foo>::value << "\n";
std::cout << std::is_trivially_copyable<Foo>::value << "\n";
std::cout << std::is_standard_layout<Foo>::value << "\n";
std::cout << std::is_pod<Foo>::value << "\n";
std::cout << std::is_literal_type<Foo>::value << "\n";
std::cout << std::has_unique_object_representations<Foo>::value << "\n";
std::cout << std::is_empty<Foo>::value << "\n";
std::cout << std::is_polymorphic<Foo>::value << "\n";
std::cout << std::is_abstract<Foo>::value << "\n";
std::cout << std::is_final<Foo>::value << "\n";
std::cout << std::is_aggregate<Foo>::value << "\n";
std::cout << std::is_signed<Foo>::value << "\n";
std::cout << std::is_unsigned<Foo>::value << "\n";
std::cout << std::is_bounded_array<Foo>::value << "\n";
std::cout << std::is_unbounded_array<Foo>::value << "\n";
}
Live
Foo is a trivial type, it is standard layout and it is a POD. It is neither polymorphic nor abstract. If you want a type that is not meant to be inherited from then you could make it final (Foo is not final).
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.
I would like to count the number of objects that my program creates over its lifetime. Based on the solution provided here:
how to count the number of objects created in c++
I have the following code:
#include <iostream>
using namespace::std;
using std::cout;
using std::endl;
template <typename T>
struct counter
{
counter()
{
objects_created++;
objects_alive++;
}
virtual ~counter()
{
--objects_alive;
}
static int objects_created;
static int objects_alive;
};
template <typename T> int counter<T>::objects_created(0);
template <typename T> int counter<T>::objects_alive(0);
class X : counter<X>
{
int a;
};
class Y : counter<Y>
{
int b;
};
void fooX(class X x) {
cout << "passing object" << endl;
}
void fooY(class Y& y) {
cout << "passing reference" << endl;
}
int main()
{
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
X x;
Y y;
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
fooX(x);
fooY(y);
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
int ui;
cin >> ui;
}
I expected that since x is passed by value, a copy of it is made inside fooX making the total number of objects of class X to be 2 while since y is passed by reference, the total number of objects of class Y to be 1.
Yet, the output of the code is as follows:
created: X:0 Y:0
alive: X:0 Y:0
created: X:1 Y:1
alive: X:1 Y:1
passing object
passing reference
created: X:1 Y:1
alive: X:0 Y:1
Why does not the number of Xs created be 2?
A copy constructor is automatically added to your counter class, and that automatically created copy constructor doesn't increment your static variables.
Write a copy constructor which does that:
counter(counter const&)
{
objects_created++;
objects_alive++;
}
Note that your destructor should probably not be virtual, unless you intend to delete dynamically created instances of derived classes via pointers or references to counter. As it stands, it's just premature pessimisation because it needlessly increases the size of your objects.
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);