I want to design a class which can store value or reference, but with the same argument in the template declaration. I can not figure out how to write the template class. Can any one give me some advise
tempalte <typename T>
class Holder {
// ......
Holder(T &value);
Holder(T value);
}
class CannotCopy {
CannotCopy(CannotCopy const&) = delete;
};
Holder<CannotCopy> holder1(CannotCopy())
CannotCopy cannot_copy;
Holder<CannotCopy> holder2(cannot_copy) // passed by reference
So if I understand you correctly, you sometimes want the class to have ownership of the element you pass into it (when constructed in place) and sometimes you want to use it as a reference to ownership stored elsewhere.
I, unfortunately, speak from experience when I tell you this is a bad idea. At first glance, this looks like a good idea, however, a few abstraction layers later you end up with code that becomes impossible to reason about the ownership.
A way of doing it is overloading your constructor on the rvalue/lvalue of the argument:
template <typename T>
class Holder {
public:
Holder(T &&value)
: m_ownership{std::make_unique<T>(std::move(value))},
m_value{*m_ownership} {}
Holder(T &value) : m_value{value} {}
private:
std::unique_ptr<T> m_ownership;
T &m_value;
};
As you can see, there now is a constructor taking a T &&
which allows you to pass an rvalue into it and it gets moved. (In the assumption a move constructor is available, which often is the case for non-copyables)
This will know it needs ownership and stores the value as a unique_ptr, to then pass a reference of the value inside of the unique_ptr in the m_value.
If you are calling the constructor with an lvalue, it simply puts it in m_value without using the unique_ptr for the ownership.
This way, your class has conditional ownership of the value. If you don't like the unique_ptr taking up space, you could (if alignment allows it -> something you could force) do some bit-manipulations to encode if you have ownership or not and write a bunch of custom code.