This looks normal for programmers coming from a java background, but for those with C++ experience, it’s awkward that the variables x_ and y_ are initialized inside the constructor body. C++ constructors using initialization lists are more correct. They go between the ) and { of the constructor, begin with a colon, and have each part separated by a comma. They style I lean towards is as follows:

Point(int a, int b)
: x_{a},
y_{b}
{ }

The difference is that rather than having x_ and y_ be default constructed, then assigned, they are copy-constructed with the values of a and b. These x_ and y_ values must have been constructed because upon entering the body of the constructor, the this object must exist.

Performance

Okay, so dealing with a couple of ints, no big deal. Let’s look at a class with a string

The semantics of this are different from what novices often think. What happens is that name_ is default constructed, and is then assigned to, and overwritten, upon entering the constructor. This means that before being assigned n, name_ already has a value! It’s the empty string! Constructing and assigning is slower than just copy constructing, so there’s a slight performance hit.

The correct constructor is, as expected

Person(const std::string& n)
: name_{n}
{ }

Objects without default constructors

Novices don’t care too much up to this point because strings and ints both can be default constructed, and strings behave very much like POD objects. However there are many objects in C++ which don’t have default constructors at all! An example? the Person class we just made!

This can’t work, because the Person class doesn’t have a default constructor. the compiler error will resemble error: no matching function for call to Person::Person(). The assignments are valid in this case, but the construction just doesn’t work. We have to use C++ style:

const, and why it’s different from final

Another case to consider, in java one may have a final instance variable, signalling that once the reference has been assigned (by the constructor) it cannot be reassigned. Some incorrectly draw a parallel between const and final, they aren’t the same.

Let’s consider a Person class where we also have a string for their social security number. This number can’t change, so we want it to be const. The java-style constructor fails here.

Remember, the semantics differ, this code default constructs ssn_ and then assigns to it. However, we can’t assign to const variables, we can only construct them (or if you prefer, initialize them). Instead we must use the correct C++ constructor style.

Since C++ novices often don’t care about constness, it’s hard to convince them to take this seriously last one seriously.

Other cases

There are other types of objects that cause problems. One is the class of objects without an assignment operator (such as the Person with a const ssn), objects where default construction followed by assignment does get expensive (std::array for example), objects that can be moved but not copied need to be handled differently, etc.

This is not an academic exercise, the problems with java-style constructors are very real.

I ran into this when implementing the C++14 version of zip for cppitertools.

Given a tuple of iterators, increment each of those iterators using ++. Assuming I already have a std::index_sequence with the indices as Is..., I initially had something like this:

void increment_all() {
++std::get<Is>(this->tup)...;
}

However, this doesn’t work because the expansion cannot appear outside of a function call or initializer list. This can be worked around with a function that absorbs everything. My original implementation was to make it variadic like so:

template <typename... Ts>
void absorb(Ts&&...) { }

this isn’t really necessary though, since we have the older … that works just as well. The below meets the requirements:

And this works for my purposes. Note that this is a function call, so the order in which the iterators will be incremented is unspecified. If it’s important to you for it to happen in a 0, 1, …, N order, then you can use an initializer list if all of the operations will return the same type, or use other solutions if they don’t.

UPDATE: I reverted to using the templated absorb because the version with just … will attempt to make copies of its input arguments. This is not what I ever want to happen. Even though the copies would be optimized out, it still prevents the function from working with non-copyable (in some cases, only non-movable) types.

Much less painful than its C++11 equivalent. std::integer_sequence is responsible for most of the ease. Combined with auto functions, which deduce their own return type, that is.

call_with_tuple first determines the tuple_size of the tuple-like object passed in. std::make_index_sequence will result in an index sequence of 0, 1, ..., TUP_SIZE. The last argument of call_with_tuple_impl is used to deduce the Is... pack. finally the mf(std::get<Is>(tup)...) is the equivalent of mf(std::get<0>(tup), std::get<1>(tup), ..., std::get<TUP_SIZE-1>(tup)).

The std::decay_t is necessary because TupType is a universal reference.

I’m using these integer sequences more and more. They’re proving to be extremely useful in flattening complex recursive data structures and logic. C++14 rules