Template member default initialization - c++

Suppose I have got the following template
template <typename T>
class{
T t;
};
Now, I want to add a constructor that initializes t with the default value for its type. That is, for numerical types, t should be initialized with 0, for pointers, t should be initialized with nullptr. Finally, there could be other types like structs. Here, a good initialization would be the default constructor (which is invoked anyway, so I do not have to do anything here).
In conlusion I am looking for something like this:
template<typename T>
class X{
T t;
X() : t(default_value<T>::value);
}
As my imaginary syntax points out, I think it could be possible with some kind of template with different specializations which carry the default values. But how to handles structs and classes? Since I have specified t(...), the default constructor is no longer an option.

You can just do
X() : t() { }
And/or this in C++11
X() : t { } { } // see Johannes Schaub's comments about this
That will value initialise (or is it default initialisation?) t to whatever the default value is for its type, be it 0 for built-in's, a series of (value?default) initialisations for arrays, or using the default constructor for user-defined types.

Related

Pass function parameter directly to class variable

I have a class lazy_segment_tree. This is the current constructor
template<typename T>
struct lazy_segment_tree{
int n;
int H;
T base;
vector<T> segtree;
vector<T> lazytree;
T (*join)(T,T);
T (*assign)(int,T,T);
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue){
join=merge;
assign=create;
base=defvalue;
n=seq.size();
}
};
Can't I directly make the construction parameters go to the values in the class variable?
I am not 100% sure what do you mean by 'directly'.
But in this case you should use initializer list to initialize the member variables. More on initializer lists here.
Applied to your code, the constructor would now look like this:
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue)
: join(merge)
, assign(create)
, base(defvalue)
, n(seq.size())
{}
In your original code, all the members are first default-constructed during initialization of the class. Then, the body of the constructor is called where you use '=' to copy assign the constructor parameters.
When initializer list is used, the members are directly constructed with specified parameters.
Depending on what T might be, it may or may not make real difference. Nevertheless, initializer lists are the standard way to initialize class members and you should use it if possible.

Why std::optional::value_or dont have a specialization for default ctor types?

std::optional<Class> a;
a.value_or( Class() ).GetMember();
Why cant we do this like:
a.value_or().GetMember();
Can standard specialize value_or on a default constructible basis?
Unfortunately this value_or doesn't have this option and I agree with with Max Langhof's comment that it should be a separate function value_or_default.
Nevertheless, as Eljay pointed out in this comment, the code from the question might cause problems for classes with expensive default construction. In cases when the optional does not carry a value, we don't want the default constructor to be called.
I've put together a little workaround for that particular case:
struct default_constructor_t {
explicit default_constructor_t() = default;
};
inline constexpr default_constructor_t default_constructor{};
class Class {
...
Class(default_constructor_t) : Class{} {}
...
};
int GetMember(std::optional<Class> Object) {
return Object.value_or(default_constructor).GetMember();
}
In this solution, you need to add an additional implicit constructor to your class. This solution is also lazy. It will call default constructor only if optional doesn't have a value.
UPD:
After a bit of thinking, I believe that I came up with a bit more generic solution that will work even with types the developer can't modify. And even if one has this ability, less code is better, right?
struct DefaultConstructed {
template <class T> operator T() const {
return T();
}
};
constexpr DefaultConstructed Default;
class Class {
...
};
int GetMember(std::optional<Class> Object) {
return Object.value_or(Default).GetMember();
}
This solution uses conversion operator instead of implicit construction. Special object named Default can be converted (so to speak) to any type by calling this type's default constructor. It also retains the nice property of the original solution to be lazy.

Initialising template variables using initializer list

I looked at a piece of code and I am trying to understand how it works and so here is a minimal working example
template <typename T>
class A
{
public:
A() : _mem(T()) {};
private:
T _mem;
};
The first thing I was not exactly clear about is the initialisation of _mem in the initialiser list. What is this technique(?) called? If I look in the debugger _mem is set to 0. If there is a c++11 way to do the same thing could I receive some comments on that?
This is just to safeguard against an uninitialized A::_mem when T is a POD type or a built-in type (like an int). Using a constructor initializer list of : _mem(T()) will default construct a T and initialize _mem with it. For example:
struct POD {
int num;
};
// ...
A<POD> a;
Here, a._mem would be unitialized (in this case, this means a._mem.num is unitialized.) The : _mem(T()) prevents that from happening and will initialize a._mem.num to 0.
However, since C++11 you can just use inline initialization instead:
template <typename T>
class A {
public:
A() {};
private:
T _mem{};
};
T _mem{}; will default-construct _mem, which in turn means POD::num will be default-constructed, which for an int means it will be zero-initialized.
If this has a name, I don't know it.
What's happening:
T() constructs a temporary T and Zero Initializes it.
_mem(T()) makes _mem a copy of the temporary T. Note: A modern compiler will almost certainly elide the copy and simply zero initialize _mem. This still requires that T be copy-or-moveable, so _mem(T()) and _mem() are not exactly the same.
The only relevant C++ 11 difference I can think of is you can use curly braces, _mem{T{}}, for List Initialization. Not useful here, but very useful in other circumstances.

C++ automatic type deduction in constructor

I am trying to understand the following code that I saw today. I already tried to find a related question, but since I have no idea what this feature of C++ is called it is hard to find related posts. A hint on the correct search term might already help me.
struct A
{ int x; };
struct B
{ B(A a) {}; };
int main()
{
B b{ { 5 } }; // works, seems to create a struct A from {5} and pass it to B's constructor
std::make_unique<B>({ 5 }); // doesn't compile
return 0;
}
Why is {5} not used to create a struct A when passed to make_unique but is used this way in the constructor of B?
If B had a second constructor B(int foo) {}; this one would be used instead of the one frome above (at least that is what I found by trial and error). What is the rule to decide if the argument is automatically used to create a struct A or if it is used directly as int in the constructor?
I am using Visual C++ 14.0
Here's a simplified demonstration:
struct X { X(int); };
void foo(X );
template <typename T> void bar(T );
foo({0}); // ok
bar({0}); // error
The issue is that braced-init-lists, those constructs that are just floating {...}s, are strange beasts in C++. They don't have a type - what they mean must be inferred from how they're actually used. When we call foo({0}), the braced-init-list is used to construct an X because that's the argument - it behaves as if we wrote X{0}.
But in bar({0}), we don't have sufficient context to know what to do with that. We need to deduce T from the argument, but the argument doesn't have a type - so what type could we possibly deduce?
The way to make it work, in this context, is to explicitly provide that T:
bar<X>({0}); // ok
or provide an argument that has a type that can be deduced:
bar(X{0}); // ok
In your original example, you can provide the A directly:
make_unique<B>(A{5})
or the B directly:
make_unique<B>(B({5}))
or just use new:
unique_ptr<B>(new B({5}))
or, less preferred and somewhat questionable, explicitly specify the template parameter:
make_unique<B, A>({5});
A constructor with a single non-default parameter (until C++11) that is declared without the function specifier explicit is called a converting constructor. Your A and B are instances of such constructors (this explains, why your first call works fine.) The problem is, that std::make_unique impedes these explicit calls. Anyhow, it might be a good idea, to not trust in these automatic creation in the first place and spent a few chars to show types. This could improve the readability of the code.

C++ / Template / Explicit init of template type?

Assume the following dummy template:
template < class DataType > class Dummy
{
public:
void init( )
{
m_data = DataType( 0 );
}
private:
DataType m_data;
};
Calling init will init the internal data. This does work fine when DataType is a standard data type (e.g. int or float). When DataType is a class this class must have a corresponding constructor.
Now assume DataType shall be e.g. a Complex Number represented by a suitable class. In this case it does not make sense to give the Complex number class a constructor with one argument because under normal conditions you want initialize real and imaginary part.
So my question is:
What is the best generic way to initialize a template type under consideration that the template shall be suitable to store any data type.
I think e.g. the STL must implement thinks like this but I am lost within that code.
In your example I guess you meant:
DataType( 0 );
Not:
Data ( 0 );
In any case, try:
m_data = DataType();
That will call the default constructor for a class type, or will zero-init for a built-in type.
You could make use of a default argument as:
template <class T>
class A
{
public:
void init(T c = T()) //default argument
{
m_data = c;
}
private:
T m_data;
};
If template argument type T is a user-defined type, and it does not define a default constructor, then you have to pass one argument to init() function yourself, otherwise you will get compilation error.
This is the approach adopted by Standard Library. For example std::vector::resize() takes an optional argument following the same rationale as mentioned above.
Effectively, you are thinking in terms of "default constructible" classes here, that is, classes that can be initialized with effectively no class-specific input. The STL is written with this term in mind, and as #DanielEarwicker wrote, the default constructor is defined for built-in types as a zero-initialization.
So, to get such a feature, your complex number class must support a default constructor, i.e. a constructor without arguments.