Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a class template store either reference or value?

Tags:

Reading about universal references led me to wonder: how can I construct a class template such that it stores by reference if possible, or by value if it must?

That is, can I do something like this

template <class T> class holder {     T  obj_m;  // should be a reference if possible... public:     holder(T t) :obj_m { t } {} }  auto  hold_this(T && t) { return holder<T>(t); } 

Except that when hold_this() is given an lvalue the holder will hold a reference, and when given an rvalue the holder will make a copy?

like image 855
aghast Avatar asked Feb 19 '18 08:02

aghast


People also ask

How do template classes work in C++?

Definition. As per the standard definition, a template class in C++ is a class that allows the programmer to operate with generic data types. This allows the class to be used on many different data types as per the requirements without the need of being re-written for each type.

What is the difference between class template and template class?

A class template is a template that is used to generate classes whereas a template class is a class that is produced by a template.

What are class templates How are they created what is the need for class templates?

The relationship between a class template and an individual class is like the relationship between a class and an individual object. An individual class defines how a group of objects can be constructed, while a class template defines how a group of classes can be generated.

Can a template class inherit from a non template class?

Deriving from a non-template base classIt is quite possible to have a template class inherit from a 'normal' class. This mechanism is recommended if your template class has a lot of non-template attributes and operations. Instead of putting them in the template class, put them into a non-template base class.


1 Answers

Except that when hold_this() is given an lvalue the holder will hold a reference, and when given an rvalue the holder will make a copy?

You already wrote it (minus the required template <typename T>). The deduction rules for a forwarding reference preserve value category as follows:

  1. If t is bound to an lvalue of type T2, then T = T2&.
  2. If t is bound to an rvalue of type T2, then T = T2.

It's those deduction rules that std::forward relies on to do its job. And why we need to pass the type to it as well.

The above means that you instantiate holder directly with T2 in the rvalue case. Giving you exactly what you want. A copy is made.

As a matter of fact, two copies are made. Once to create the constructor argument t, and the other copy is to initialize obj_m from it. But we can get rid of it with some clever use of type_traits:

template <class T> class holder {     T  obj_m;  // should be a reference if possible... public:     holder(std::add_rvalue_reference_t<T> t) :obj_m { std::forward<T>(t) } {} };  template<typename T> auto hold_this(T && t) { return holder<T>(std::forward<T>(t)); } 

See it live. We use add_rvalue_reference_t to make t be of the correct reference type in each case. And "simulate" the argument deduction which would make obj_m { std::forward<T>(t) } resolve to initializing obj_m from the correct reference type.

I say "simulate" because it's important to understand the constructor argument for holder cannot be a forwarding reference because the constructor itself is not templated.


By the way, since you tagged c++17, we can also add a deduction guide to your example. If we define it as follows (with the feedback from T.C. incorporated):

template <class T> class holder {     T  obj_m;  // should be a reference if possible... public:     holder(T&& t) :obj_m { std::forward<T>(t) } {} };  template<typename T> holder(T&&) -> holder<T>; 

Then this live example shows you can define variables as hold h1{t}; and hold h2{test()};, with the same deduced types as the function return values from before.

like image 139
StoryTeller - Unslander Monica Avatar answered Sep 22 '22 17:09

StoryTeller - Unslander Monica