Default arguments and overload resolution

Default arguments can be a surprisingly lengthy subject. What I want to cover here is more to do with how they work with declarations and inheritance. We’ll start by looking at overload resolution, then introduce default arguments, and finally virtual functions.

Overload resolution
It’s the process of selecting the best function to call based on the arguments of the function call (or the expressions which will result in the arguments) and the set of candidate function which could be called based on the call site [over.match / 13.3]. It’s a 2 step process:

1. The set of viable functions is determined based on the functions meeting the number of arguments and other criteria.
2. The best viable function is selected based on the implicit conversion rules to match each argument to the respective parameter of each viable function.

An interesting note is that accessibility is never considered. Meaning the best viable function for a call could be inaccessible, if say it was declared private. It would be considered ill-formed and your compiler should complain.
Continue readingDefault arguments and overload resolution

Phases of Translation

I recently came across a mention about translation when reading about constexpr. Namely that the value of a constexpr objects (constexpr functions are a bit different) can be evaluated during translation. Hence the inspiration to dig a bit deeper. If you’re like me, you know about the inputs of translation and it’s final output, but what about the different steps?

To rewind, a program consist of one or more translation units which are linked together. What’s included in a translation unit? It includes a source file, its headers, and everything else added by #include directives. How we turn the raw lines of code we programmers write, into these translation units is defined in 9 “easy” steps in the standard [lex.phases / 2.2].

Step 1: The source file characters are mapped to the basic source character set.
Continue readingPhases of Translation

Same same: Covariant return types.

In this post, I want to talk about a specific feature. To set the table, it has to do with the return type of virtual functions. The compiler usually enforces that the return type of an override method match exactly the type of the base method declaration. However, there is a little leeway, with covariant return types. This is an interesting feature in C++ which isn’t supported in C#. In a nutshell, it allows the overriding method to change the return type, as long as it is a covariant return type. For example:

class Y {};
class Z : public Y {};

struct A {
   virtual Y* foo() { return new Y(); }
};
struct B : public A {
   Z* foo() { return new Z(); } // legal code. Notice the 
                                // change of return type. 
};

This follows the Liskov Substitution Principle (LSP) very nicely, since class Z IS A class A and can be substituted as such. The standard explains this in section [class.virtual / 10.3 ] paragraph 7. This is where the conditions placed on using covariant return types are outlined:

Continue readingSame same: Covariant return types.

Adaptor Containers : What’s under the hood.

C++14 outlines 3 container adaptors: stack, queue, priority_queue. They are outlined in section [container.adaptors/23.6]. If you take a look at their constructors, you’ll notice they’re implemented in terms of other containers. Hence the “adaptor” part of their name. Looking specifically at queue, the constructor has a default parameter set to a deque, but allowing the parameter to be set to another type. Here’s the declaration:

template <class T, class Container = deque <T> >
class queue;

Your first question may be:
“Why does stack use a deque as its default underlying container?”

Your second question may be:
“What other types of containers should you use?”

If we look a the usage of a queue, we expect to be able to insert elements at the back of the container, remove from the front of the container, and read from both ends of the queue. Explicitly, this means an interface supporting front(), back(), pop_front(), push_back(). Let’s look at the available sequence containers [sequences / 23.2]: array, deque, forward_list, list, vector.

Continue readingAdaptor Containers : What’s under the hood.”

Short circuits and the evaluation order of function parameters

This post isn’t about our favorite old school robot Johnny 5. So let’s start with the second part: the non defined order of evaluation of function parameters (yes, it’s non defined)

if(A(C()), B())

The compiler is free to evaluate A(), then B(), C(), or B(), then C(), then A(), etc. This could be troublesome if you expect a variable to be initialized in A() to be used in B(). The one guarantee is that C() is evaluated before A().

Another item which has some fun with the order of evaluations are the logical operators. Probably a bit of an “yeah, makes sense”, but worth the refresher.

operator || and operator && won’t necessarily evaluate all their arguments. This is known as “Short circuit evaluation”. For example:
Continue readingShort circuits and the evaluation order of function parameters

vector < bool >: What isn’t can’t be.

vector<bool> doesn’t behave like other STL containers. If you try to obtain a reference to a bool inside the container, you’ll end up with an rvalue. Probably not what you had in mind. Oddly, it IS standard compliant (more on this later). Therefore you can’t say it’s not “standard compliant” container. What it doesn’t follow is the optional sequence container operations format from table 101 in section [sequence.reqmts / 23.2.3]. This table states the format for operator [] to return a reference or a const_reference. Assuming in this case vector<T>, a reference would be a T& and a const_reference a const T&. In the case of vector<bool>, operator[] returns a “reference” which is a class (more on this later). So there you have it. vector<bool> is standards compliant, but doesn’t meet the container requirements.

Continue readingvector < bool >: What isn’t can’t be.