Little wonders of C++ (9)

C++ is transforming into a better language, that is even more powerful than before and much easier and robust to write.

Now that we've seen how useful the STL is, we come back to focus on real language features. This time three C++14 features will be on the list. Additionally two golden classics are also packed in.

We will start with an essential one: The compatibility to C - not in a language sense, but ABI-wise. Of course C++ allows us to use ABI easily. However, providing such interfaces seems to be tricky with namespaces, classes, overloads and other options. The first section shows how it can be achieved.

Finally the issue of private inheritance will be investigated. We will see, that this feature does not only impose a certain meaning on the considered type, but also has a very special purpose. Without further words, let's just dive into the second to last post about little wonders of C++!

C compatible APIs

C++ has many layers. A crucial layer is the strong correspondence to C. While technically being no (strict) superset of C, C++ offers everything one finds in C. In the early days C++ has even been compiled with a C compiler using macros and magic. Any C++ application can therefore include C header files and link against object files, that have been produced by any C compiler.

The question now is: Is it then also possible, to link against C++ headers from C? In general, of course, it is not. Templates, classes, namespaces and a lot more features are not available in C, and will lead to compilation errors. Nevertheless, if we restrict ourselves to functions and elementary types, that might work, right? Here it becomes tricky.

On the one hand C++ has function overloading, on the other hand C++ has a naming system, that is different from C. At this point it seems hopeless to use a C++ created API / functionality in C. This is where the magic starts. C++ has a way to tell the compiler, that naming should be the same as in C.

extern "C" void foo(int);
extern "C" {
  void g(char);
  int i;
}

The first line declares the function foo as being a C style function. This only has implications on the assembly level. We can still use C++ code within the specified function. If we want to write a lot of functions, specifying extern "C" in front of every declaration is tedious and not very elegant. We can alleviate the situation by grouping these functions in a block statement that follows the extern "C".

However, if the header file is directly included in C, the linkage specification might lead to errors. Therefore the following block is recommended:

#ifdef __cplusplus
extern "C" {
#endif
  void g(char);
  int i;
#ifdef __cplusplus
}
#endif	

Looks a lot more ugly, but it is for a good reason. The C compiler will now ignore the linkage specification as it will already provide C style naming. However, if we compile the original source code with a C++ compiler, the preprocessor conditionals will be active and C++ style naming will be turned off in favor of C style naming.

There are natural restrictions to linkage specifications. A linkage specification shall occur only in namespace scope. Only function names and variable names with external linkage have a language linkage. Interestingly two function types with distinct language linkages are distinct types even if otherwise identical. And obviously the linkage is ignored for class members. Finally keywords available in C++ are not allowed, even though they would be in the target language. The rules of C++ still apply in the given section.

Return Type Deduction

The introduction of auto in C++11 was a great success. Code is now more flexible, maintainable and extensible than before. In my opinion it is also easier to read, since more percent of the space is used for actual code, i.e. code that includes functionality. With all these great compiler assistance in mind, wouldn't it be great to also provide auto as the return type? After all we have already this deduction in lambda expressions...

Therefore C++14 introduces return type deduction. It is just a little feature, but it will make a lot of sense. The basic rule is: By looking at the function (name, content) it should be obvious what to expect.

Some examples:

auto magic_number() {
  return 42u;
}

Alright, a first guess would be that such functions never appear. But they do appear. Sometimes they only appear to provide a place holder for later refinement. Sometimes due to polymorphism. Whatever the reason is, deducing it to an unsigned integer is pretty straight forward.

template<typename Targ1, typename Targ2>
auto add(Targ1 a, Targ2 b) {
  return a + b;
}

I don't know what that result type is. One would be required to look at the definition of operator+(Targ1, Targ2) if there is any. Either way, before the auto return type deduction we would have used decltype, which is much harder to read. And we would still be required to resolve the type by finding the defined operator.

auto mappings() {
  std::vector<std::map<int, std::pair<int, double>>> elements { };
  /* ... */
  return elements;
}

Alright, this is an ugly type. What would be even uglier? Repeating it. This kind of redundancy could be killed with a typedef, but then we would be required to find the definition. I think using auto is much better to read and let's us focus on the important parts of the function.

Generic Lambdas

C++14 will improve the lambda expressions introduced by C++11. There are capture expressions, return type deduction for multiple statements and more. A neat feature that provides interesting possibilities is a generic lambda.

Let's consider the following snippet:

auto lambda = [](auto x, auto y) { return x + y; };

Alright, so what to put in there? This way the function could also be taken from a JavaScript code! But C++ has a static type system. The compiler creates a structure that contains a template function instead of a normal one. We have:

struct unnamed_lambda {
  template<typename Targ1, typename Targ2>
  auto operator()(Targ1 a, Targ2 b) const {
    return x + y;
  }
};

auto lambda = unnamed_lambda { };

I think this is a stupendous feature and offers a lot of interesting possibilities. In the end, it is just a little addition, but highly appreciated if needed.

Binary Literals and digit separators

A great thing about the D programming language is the support for binary literals. It took some time, but now other programming languages are also included binary literals. The next version of C# will also contain them. Python has them for some time and even Java already added them. The syntax is practically the same as in these other languages:

const auto value = 0b1000010011000110;

That is quite hard to read. The exact value of 33990 seems to be much easier. The problem is that binary literals tend to use a lot of space. After all we require one character just to specify a single bit. And there are many bits...

The solution is really easy: A custom separator that can be used arbitrarily in numeric literals. The good thing is, that such a separator is independent of the literal, i.e. we can also use it in standard integer or floating point literals. C# uses the underscore as a separator. I like that choice very much. However, the language design team of C++ couldn't consider that choice, since the underscore can be used for custom literals. Therefore we have to live with another way of solving this problem: the apostrophe character.

auto integer_literal = 1'000'000;
auto floating_point_literal = 0.000'015'3;
auto binary_literal = 0b0100'1100'0110;
auto silly_example = 1'0'0'000'00;

According to the specification there cannot be two or more consecutive separators. Additionally a separator has to be preceded and followed by a valid digit. In my opinion this is a useful feature, however, with limitations compared to the one in C#.

Private inheritance and EBO

Let's get back to the basics. C++ has a quite unique way of inheritance. We do not only use the inheritance operator :, but also a keyword that is usually stated for encapsulation reasons: namely public or private. But why private? The meaning of public inheritance is obvious. It is in no way different than in other languages such as Java or C#. But private is different...

By applying a private inheritance we do the same stuff as with public inheritance, however, instead of mapping public to public and protected to protected, we map public and protected to private. In both versions we omit private members of the base class.

It is also already obvious that from a certain perspective, private inheritance is not the classic "is-a" relationship. Why? We cannot access public members of the base class from outside the class. What is it then? It is a basically another way of doing composition.

Usually classes are composed of other classes by creating fields that represent instances of these classes. This allows us to use the public API of these classes. However, we cannot use the methods and fields marked as protected. Obviously there are some good OOP reasons for that. But C++ also has friend functions / classes and more. Therefore I ask the question: Is encapsulation our real concern here?

There is also protected inheritance. It is essentially the same as with private, however, the corresponding functions will be mapped to protected access modifiers instead of private ones. The following example illustrates this:

class A {
public:    int x;
protected: int y;
private:   int z;
};

class B : public A {
  // x is public
  // y is protected
  // z is not accessible from B
};

class C : protected A {
  // x is protected
  // y is protected
  // z is not accessible from C
};

class D : private A {
  // x is private
  // y is private
  // z is not accessible from D
};

Protected inheritance is rarely useful. But private inheritance could be quite handy. Why is that? First, accessing protected members could useful. But again: A discussion about encapsulation is probably not what we are after. Second, there might be performance benefits. C++ does not know how to handle empty objects. Therefore even an empty class will be filled with a single byte. Including a lot of objects that are empty on a first glance, may be not so ideal. However, C++ does have an optimization technique called empty base optimization (EBO). This technique is applied when we inherit from an empty class.

EBO leaves the base empty if the child is non-empty. This is great! When is it used a lot? Empty type traits that only contain functions will make use of the EBO. Sometimes containment is the better solution, though. Nevertheless, e.g. the size for strings is critical - so it's an often seen usage with strings.

Created . Last updated .

References

Sharing is caring!