Category Archive for C++

const auto* versus const auto for Pointer Types

When working with references, C++ developers have been trained to use auto&, const auto&, or auto&& to avoid copies being made. However, when dealing with pointers, developers often do not use auto* but simply use auto instead. With pointers, there is no danger that you make accidental copies of the data, but there are other issues with omitting the *. Also, when working with pointers, there is a big difference between using const auto versus const auto*.

Let’s assume you have the following simple classes:

#include <memory>

class Data {};

class Foo
{
public:
	Foo() : m_data(std::make_unique<Data>()) { }

	Data* GetData() { return m_data.get(); }

private:
	std::unique_ptr<Data> m_data;
};

The GetData() method simply returns a pointer to a Data instance.

When using auto, a lot of developers simply write the following:

Foo foo;
auto d1 = foo.GetData();

The resulting type of d1 is Data*.

I actually recommend to write the following instead:

auto* d2 = foo.GetData();

d2 is also of type Data*, but the benefit is that you immediately see that you are dealing with a pointer. I know, in most IDE’s you can simply hover your mouse over the variable name and it will tell you the exact type. However, sometimes you are not working in an IDE. One such example is when doing code review in an external tool. Most of these tools do not show you that information when hovering over the name of a variable. This makes it a bit more difficult during code review to know that d2 is actually a pointer. When you write auto*, then it’s immediately obvious.

Now, let’s throw const into the mix. Again, most developers will not write the * with auto, so they write the following:

const auto d3 = foo.GetData();

However, this is most of the time not doing what you expect it to do!
Often, when you use const, you want to protect the thing to which the pointer is pointing to. A lot of developers assume that d3 is of type const Data*, but in fact, the type is Data* const, so it’s a const pointer to a non-const Data! Putting the const after the auto as follows doesn’t help, the type is still Data* const:

auto const d4 = foo.GetData();

When you use auto* in combination with const, then it’s behaving as you would expect. For example:

const auto* d5 = foo.GetData();

With this line, d5 is of type const Data* 🙂

If you really want a const pointer instead of const data, you put the const at the end:

auto* const d6 = foo.GetData();

d6 has type Data* const.

And finally, with this syntax you can make both the pointer and the data constant:

const auto* const d7 = foo.GetData();

d7 is of type const Data* const. You cannot achieve this if you omit the *.

All this is something to keep in mind. I’ve seen developers make mistakes against this several times.

Share

Visual Studio 2017 version 15.8 Preview 3 Released

On June 26, 2018, Microsoft released version 15.8 Preview 3 of Visual Studio 2017. Read the announcement here. A few points worth mentioning:

  • Project Loading: Visual Studio version 15.8 Preview 3 brings faster project reloads for all types of projects. Benefits are huge – project unload and reload that used to take more than a minute for large solutions now takes just a few seconds.
  • C++ Templates IntelliSense: Visual Studio 2017 version 15.8 Preview 3 brings IntelliSense for Templates.
  • C++ Refactoring: A new quick-fix lightbulb to convert basic macros to constexpr as a new tool to modernize your C++ code.
  • Improvements for the C++ code analysis tools.
  • C++ Standards: A new, experimental, token-based preprocessor that conforms to C++11 standards (including C99 preprocessor features), enabled with /experimental:preprocessor switch.

Also interesting to know, since 15.7, Visual C++ conforms with the C++ Standard. Read more about this here.

Share

C++17: Attributes

C++17 introduces three new code attributes:

  • [[fallthrough]]
  • [[maybe_unused]]
  • [[nodiscard]]

The first one was discussed in detail in my C++17: Fallthrough in switch statements blog post. The others are briefly explained below.

[[maybe_unused]]

This attribute can be used to mark variables or functions that might be unused to avoid the compiler from generating a warning for such variables and functions.

For example, suppose you have code as follows:

bool DoSomething()
{
    // ... do something ...
    return true;
}

int main()
{
    bool result = DoSomething();
    assert(result);
}

When you build a release build of your code, the assert() macro becomes a no-operation. As such, in release builds, the result variable is unused, while in debug you need the result variable for the assert(). To avoid the compiler warning, use the [[maybe_unused]] attribute as follows:

int main()
{
    [[maybe_unused]] bool result = DoSomething();
    assert(result);
}

This attribute can also be used on functions. Maybe you have a function that is only executed in debug. In such a case, you can mark the function with the attribute. For example:

static bool OnlyUsedInDebug() { return true; }

int main()
{
    assert(OnlyUsedInDebug());
}

When compiling with gcc, the compiler gives the following warning:

warning: ‘bool OnlyUsedInDebug()’ defined but not used [-Wunused-function]

The avoid this warning, use [[maybe_unused]]:

[[maybe_unused]] static bool OnlyUsedInDebug() { return true; }

[[nodiscard]]

This attribute can be used to make sure the caller of a function does not just discard the return value of that function. For example:

bool DoSomething() { return true; }

int main()
{
    DoSomething();
}

The user is not doing anything with the return value of the DoSomething() function, but the compiler will not give any warning about this. Now, the following code adds the [[nodiscard]] attribute:

[[nodiscard]] bool DoSomething() { return true; }

When you try to call it as in the previous main() function, the compiler will complain with something as follows:

warning C4834: discarding return value of function with ‘nodiscard’ attribute

Share

Fixing Unreadable Window Titles in Maximized MFC Ribbon Bar Applications

If you use MFC to create an MFC ribbon bar application, you might notice that when you maximize your application, that the text in the window title bar has a different color compared to a non-maximized window. For example, here is a screenshot of a non-maximized default MFC ribbon bar application created by the Visual Studio project wizard:

When you maximize the window, the result could be as follows:

The text in the title bar becomes white, while it was black in the non-maximized window.
This is a long-standing bug in MFC. Luckily, there is an easy workaround for it. I’ll be using the Windows 7 MFC theme, but similar workarounds can be implemented for the other themes.

First, you need to derive your own class from CMFCVisualManagerWindows7 and override two methods: DrawNcText() and DrawTextOnGlass(). Here is the code:

#pragma once

class CMyVisualManager7 : public CMFCVisualManagerWindows7
{
	DECLARE_DYNCREATE(CMyVisualManager7)

	virtual void DrawNcText(CDC* pDC, CRect& rect, const CString&
		strTitle, BOOL bActive, BOOL bIsRTL, BOOL bTextCenter, BOOL bGlass = FALSE,
		int nGlassGlowSize = 0, COLORREF clrGlassText = (COLORREF)-1) override;

	virtual BOOL DrawTextOnGlass(CDC* pDC, CString strText, CRect rect,
		DWORD dwFlags, int nGlowSize = 0, COLORREF clrText = (COLORREF)-1) override;
};

And here is the implementation:

#include "stdafx.h"
#include "MyVisualManager7.h"

IMPLEMENT_DYNCREATE(CMyVisualManager7, CMFCVisualManagerWindows7)

void CMyVisualManager7::DrawNcText(CDC* pDC, CRect& rect, const CString&
	strTitle, BOOL bActive, BOOL bIsRTL, BOOL bTextCenter, BOOL bGlass /*= FALSE*/,
	int nGlassGlowSize /*= 0*/, COLORREF clrGlassText /*= (COLORREF)-1*/)
{
	if (bGlass && afxGlobalData.bIsWindows7)
	{
		// If we're drawing text on the DWM caption and Windows is Win7 or later, always use default text color
		// (in WinVista, the maximized "aero" caption was black):
		clrGlassText = (COLORREF)-1;
		nGlassGlowSize = 10;
	}

	__super::DrawNcText(pDC, rect, strTitle, bActive, bIsRTL,
		bTextCenter, bGlass, nGlassGlowSize, clrGlassText);
}

BOOL CMyVisualManager7::DrawTextOnGlass(CDC* pDC, CString strText, CRect rect,
	DWORD dwFlags, int nGlowSize /*= 0*/, COLORREF clrText /*= (COLORREF)-1*/)

{
	if (afxGlobalData.bIsWindows7)
	{
		// If we're on Windows 7 or later, always use default color.
		clrText = (COLORREF)-1;
		nGlowSize = 10;
	}

	return __super::DrawTextOnGlass(pDC, strText, rect, dwFlags,
		nGlowSize, clrText);
}

The overridden DrawNcText() method makes sure that the text for the window title is correct, while the overriden DrawTextOnGlass() method makes sure that Quick Access Toolbar controls with
text labels have the correct color.

Once you have your derived class, you have to use it. Your application probably contains something as follows:

CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));

Just replace CMFCVisualManagerWindows7 with your CMyVisualManager7:

CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMyVisualManager7));

That’s it.
Just compile and run your application. When you now maximize your window, the color in the title bar will be correct.
For example, here is the previous window maximized:

Looks much better 🙂

Share

C++17: std::string_view

If you have to write a function that accepts a string, what type of parameter will you use? You have a couple of choices:

  • const std::string&: downside is that whenever you call the function, an std::string is expected. If you pass a const char*, an std::string instance will be created implicitly for you.
  • const char*: downside is that if your caller has an std::string, they will have to use c_str() on it to pass a const char* to your function.
  • A const char* overload and a const std::string& overload: downside is that you have to implement two functions. This solution quickly becomes unwieldy if you are writing a method that accepts more than one string as parameter. For example, suppose your method requires two strings as parameters. If you want to overload the method to provide all possible combinations of input argument types, then you end up writing four versions: (const char*, const char*), (const char*, const string&), (const string&, const char*), and (const string&, const string&). This only becomes worse with even more string parameters.

C++17 makes it easy by introducing a new type called std::string_view. From now on, if you are writing a function that accepts a string, use an std::string_view as parameter type. No need to use an std::string_view reference. A string_view is very cheap to copy, so it’s perfectly fine to pass by value. Basically, a string_view just contains a pointer to a string, and its length. A string_view parameter accepts any kind of string, such as a C++ std::string, a C-style const char* string, and a string literal, all without any copying involved!

std::string_view is defined in the <string_view> header. It has a similar interface as the well-known std::string class. However, since a string_view is a read-only view of a string, only the const operations of std::string are supported on a string_view. Additionally, a big advantage of a string_view is that it will never copy a string.

Here is a very brief example of its usage:

#include <iostream>
#include <string_view>

using namespace std;

void ProcessString(string_view myString)
{
    cout << myString; if (myString.size() >= 4)
    {
        cout << "   (Substring: " << myString.substr(2, 2) << ")";
    }
    cout << endl;
}

int main()
{
    string myString1 = "Hello";
    const char* myString2 = "C++";
    ProcessString(myString1);  // C++ string
    ProcessString(myString2);  // C-style string
    ProcessString("World!");   // String literal
}

The output of this piece of code is as follows:

Hello   (Substring: ll)
C++
World!   (Substring: rl)

My book, Professional C++, 4th Edition, explains the std::string_view class in a bit more details. Additionally, it explains all new C++17 features, and much more.

Share

C++17: Fallthrough in switch statements

A C++ switch statement allows execution to fall through from one case to the next case when a break statement is missing. For example:

#include <iostream>

using namespace std;

enum class Mode
{
    Default,
    Custom
};

class Parameters {};

Parameters AskUserForCustomParameters()
{
    cout << "Asking user for custom parameters..." << endl;
    return Parameters();
}

void Process(const Parameters& parameters)
{
    cout << "Processing parameters..." << endl;
}

void DoSomething(Mode mode)
{
    Parameters parameters;  // Create a default set of parameters
    switch (mode)
    {
    case Mode::Custom:
        AskUserForCustomParameters();
    case Mode::Default:
        Process(parameters);
        break;
    }
}

int main()
{
    DoSomething(Mode::Custom);

    cout << endl;

    DoSomething(Mode::Default);
}

Of course, in this case we could just have used an if statement, but that wouldn’t demonstrate fallthrough in switch statements.

If you look at the code, the case for Mode::Custom does not contain a break statement. Some compilers will issue a warning for this kind of fallthrough because it might be unintended and a source of bugs. C++17 introduced a [[fallthrough]] attribute that you can use to specify in code that a fallthrough is intentional and should not generate a warning. Here is the modified fragment:

void DoSomething(Mode mode)
{
    Parameters parameters;  // Create a default set of parameters
    switch (mode)
    {
    case Mode::Custom:
        AskUserForCustomParameters();
        [[fallthrough]];
    case Mode::Default:
        Process(parameters);
        break;
    }
}

You don’t need to use the [[fallthrough]] attribute for empty switch cases. No compiler will issue a warning for fallthrough with empty case statements. For example:

enum class Mode
{
    Default,
    Custom,
    Standard
};

void DoSomething(Mode mode)
{
    Parameters parameters;  // Create a default set of parameters
    switch (mode)
    {
    case Mode::Custom:
        AskUserForCustomParameters();
        [[fallthrough]];
    case Mode::Standard:
    case Mode::Default:
        Process(parameters);
        break;
    }
}

My book, Professional C++, 4th Edition, explains all new C++17 features, and much more.

Share

C++17: std::byte

What is it?

C++17 introduced a new type: std::byte.

Previously, when you needed to access raw memory, you would use an unsigned char or a char data type. However, these data types give the impression that you are working with characters or with numeric values. The new std::byte data type does not convey character or arithmetic semantics, it is just a collection of bits. As such, it’s ideal to represent raw memory. An std::byte only supports initialization from an integral type, and can be converted back to an integral type using std::to_integer(). The only other operations supported are bit-wise operations. Both std::byte and std::to_integer() are defined in <cstddef>.

How to use it?

Let’s look at some short examples. First, here is how you can initialize an std::byte:

#include <cstddef>

int main()
{
    std::byte myByte{ 2 };
}

Next, you can use std::to_integer() to convert an std::byte back to an integral type of your choice:

#include <iostream>
#include <cstddef>

int main()
{
    std::byte myByte{ 2 };
    std::cout << std::to_integer<int>(myByte) << std::endl;
}

The following bitwise operations are supported: <<, >>, |, &, ^, ~, and <<=, >>=, |=, &=, and ^=. Here is an example:

#include <iostream>
#include <cstddef>

using namespace std;

void PrintByte(const byte& aByte)
{
    cout << to_integer<int>(aByte) << endl;
}

int main()
{
    byte myByte{ 2 };
    PrintByte(myByte);	// 2

    // A 2-bit left shift
    myByte <<= 2;
    PrintByte(myByte);	// 8

    // Initialize two new bytes using binary literals.
    byte byte1{ 0b0011 };
    byte byte2{ 0b1010 };
    PrintByte(byte1);	// 3
    PrintByte(byte2);	// 10

    // Bit-wise OR and AND operations
    byte byteOr = byte1 | byte2;
    byte byteAnd = byte1 & byte2;
    PrintByte(byteOr);	// 11
    PrintByte(byteAnd);	// 2
}

Why use it?

You might wonder what the difference is with just using the existing uint8_t instead of std::byte. Well, std::byte is really just a bunch of un-interpreted bits. If you use uint8_t, you are actually interpreting the bits as an 8-bit unsigned numerical value, which might convey the wrong semantics. Also, std::byte will not allow accidental arithmetic on it, while uint8_t does.

Raw memory buffers and interoperability with legacy C-style API’s

If you need a buffer of raw memory, then you can use std::vector<std::byte>.

Additionally, if you need to pass such a buffer to a legacy C-style API accepting, for example, an unsigned char*, then you will have to add a cast. Here is a brief example:

void SomeCApi(unsigned char* buffer, unsigned int size)
{
    for (unsigned char index = 0; index < size; ++index) {
        buffer[index] = index;
    }
}

int main()
{
    std::vector<std::byte> buffer{ 100 };
    SomeCApi(reinterpret_cast<unsigned char*>(&buffer[0]), buffer.size());

    for (const auto& element : buffer) { PrintByte(element); }
}

Conclusion

When you are working with raw bits, use an std::byte instead of an unsigned char or char data type.

Share

Next BeCPP UG Meeting Planned For June 28th, 2018

The next meeting of the Belgian C++ Users Group is planned for Thursday June 28th, 2018 at 18:00 at Amplidata.

Amplidata, a Western Digital company, ( http://amplidata.com/ ) is sponsoring this event by providing the location, drinks and catering.

Amplidata Logo

The agenda is as follows:

  • 18:00: Sandwiches.
  • 18:30: Session 1: Strongly Typed Declarative Bitsets in C++17 (Ewoud van Craeynest)
    The C++ standard states that bool values behave as integral types, that they participate in integral promotions and conversions.
    As a community, we reached the consensus that those integral types aren’t particularly type safe. So, neither are our bools, neither are our bitsets, nor the bits within a bitset. Numbers just being numbers can lead to subtle bugs and impede merciless refactoring.
    This session aims to introduce a strongly typed, declarative bitset type using C++17, by looking at a strongly typed bool and template offset bitfields first.
  • 19:30: Break
  • 19:45: Session 2: The Observer pattern and boost.signals2 (Lieven de Cock)
    The Observer pattern, is one of the many famous GOF design patterns. We will take a look at a minimal implementation, and then enhance that implementation a bit. We briefly touch some potential problems and think about options on how to deal with them. Then we look at a way of avoiding boiler plate code, by using the boost.signals2 library. This header-only boost library will take care of much administration work so we don’t need to reinvent the wheel. No prior knowledge is needed of the observer design pattern, nor the boost.signals2 library.
    Just bring your C++ (11-14-17) skills and … observe.
  • 20:45: Introduction to Amplidata, followed by a drink.

Professional C++, 4th Edition
We will be giving away 2 copies of the recently published new edition of Professional C++, the 4th Edition.

JetBrains
We will also be giving away a JetBrains coupons for 100% discount of a 1 year free personal subscription for any single JetBrains tool/IDE JetBrains.

The event is free for everyone, but you need to register for it.

There are 70 seats available for this event.

Note: The deadline for registrations is June 24th, 2018!

Share

“Professional C++, 4th Edition” Released

It has been a lot of work, but I’m proud to announce my fourth edition of “Professional C++” 🙂
It is published by Wiley/Wrox.
And already available at Amazon.

Official Description

Get up to date quickly on the new changes coming with C++17

Professional C++ is the advanced manual for C++ programming. Designed to help experienced developers get more out of the latest release, this book skims over the basics and dives right in to exploiting the full capabilities of C++17. Each feature is explained by example, each including actual code snippets that you can plug into your own applications. Case studies include extensive, working code that has been tested on Windows and Linux, and the author’s expert tips, tricks, and workarounds can dramatically enhance your workflow. Even many experienced developers have never fully explored the boundaries of the language’s capabilities; this book reveals the advanced features you never knew about, and drills down to show you how to turn these features into real-world solutions.

The C++17 release includes changes that impact the way you work with C++; this new fourth edition covers them all, including nested namespaces, structured bindings, string_view, template argument deduction for constructors, parallel algorithms, generalized sum algorithms, Boyer-Moore string searching, string conversion primitives, a filesystem API, clamping values, optional values, the variant type, the any type, and more. Clear explanations and professional-level depth make this book an invaluable resource for any professional needing to get up to date quickly.

  • Maximize C++ capabilities with effective design solutions
  • Master little-known elements and learn what to avoid
  • Adopt new workarounds and testing/debugging best practices
  • Utilize real-world program segments in your own applications

C++ is notoriously complex, and whether you use it for gaming or business, maximizing its functionality means keeping up to date with the latest changes. Whether these changes enhance your work or make it harder depends on how well-versed you are in the newest C++ features. Professional C++ gets you up to date quickly, and provides the answers you need for everyday solutions.

Share

Next BeCPP UG Meeting Planned For February 28th, 2018

The next meeting of the Belgian C++ Users Group is planned for Wednesday February 28th, 2018 at 18:00 at Nokia.

Nokia ( http://nokia.be/ ) is sponsoring this event by providing the location, drinks and catering.

Nokia Logo

The agenda is as follows:

  • 18:00: Sandwiches.
  • 18:30: Session 1: Boost.Asio C++ (Network) Programming (Part 2) (Lieven de Cock)
    Boost.Asio is a cross-platform C++ library for network and low-level I/O programming, either using a synchronous or asynchronous model. We will examine this powerful library in 2 sessions.
    In this second session we will pick up where we left of, after connecting as a client we will start interacting with the server, and we will see how to implement a server application.
    We will do this both in a synchronous and an asynchronous way, keeping an eye on scalability.
    Note that the C++ Standard networking proposals are based directly on Boost.Asio, so next to learning this great library we are also preparing for the future C++ standard.
  • 19:30: Break
  • 19:45: Session 2: A possible future for embedded (Odin Holmes)
    Through the much-hyped advent of Industry 4.0 and IoT, billions of new bare metal devices will be connected to the internet or intranets and will be expected to talk to each other, even across company boundaries. This presents a plethora of new challenges, many of which share a common root; it is crucial that we build a foundation for code reuse and encapsulation of expertise in this domain. What does cross-platform code really mean when we are targeting thousands of ‘platforms’? When encapsulating expertise, we implicitly make assumptions about user code and user code implicitly makes assumptions about library code. What are valid assumptions? What is the basic interface? In this talk I will present a possible future for bare metal development which attempts to answer these questions.
  • 20:45: Introduction to Nokia, followed by a drink.

C++ Standard Library Quick Reference
We will be giving away a copy of C++ Standard Library Quick Reference.

The event is free for everyone, but you need to register for it.

There are 60 seats available for this event.

Note: The deadline for registrations is February 25th, 2018!

Share

C++17: Initializers for if & switch statements

Two small, but very useful C++17 features are initializers for if and switch statements. These can be used to prevent polluting the enclosing scope with variables that should only be scoped to the if and switch statement. The for statement already supports such initializers since the beginning.
For example, suppose you are using a map to store the number of times a certain name occurs:

#include <cstddef>
#include <map>
#include <string>
#include <iostream>

int main()
{
    std::map<std::string, size_t> nameCounters{
        {"Marc", 5},
        {"Bob", 12},
        {"John", 3}
    };

    auto result = nameCounters.find("Bob");
    if (result != cend(nameCounters))
        std::cout << "Count: " << result->second << std::endl;
}

In this example I’m searching for a key in the map, and if the key is found, I output the associated value to the console. The result of calling find() is stored in result, but this variable is only used inside the if statement.
With C++17, you can initialize the result variable with an if statement initializer so that the result variable is only known inside the if statement and does not pollute the enclosing scope with unnecessary variables:

#include <cstddef>
#include <map>
#include <string>
#include <iostream>

int main()
{
    // ... Initialize map as before ...

    if (auto result = nameCounters.find("Bob"); result != cend(nameCounters))
        std::cout << "Count: " << result->second << std::endl;
}

Similar kind of initializers are supported for switch statements:

switch (<initializer>; <expression>) { /* ... */ }
Share

BeCPP Event January 9th, 2018

Barco has created a nice flyer for the Belgian C++ Users Group event of January 9th 2018.

Share

Next BeCPP UG Meeting Planned For January 9th, 2018

The next meeting of the Belgian C++ Users Group is planned for Tuesday January 9th, 2018 at 18:00 at Barco.

Barco ( https://www.barco.com/ ) is sponsoring this event by providing the location, drinks and catering.

Barco Logo

The agenda is as follows:

  • 18:00: Sandwiches.
  • 18:30: Session 1: Threads are evil (Frederik Vannoote)
    Many applications beyond the scope of “Hello World” use threads for various reasons. Be it for having many sequential execution paths, preventing a blocked UI or offloading CPU intensive tasks to the background.
    However threads don’t come for free. They suddenly add a complex dimension to a simple application. Who dares to claim to have written a flawless threaded application? Is it really bringing a performance boost?
    Let’s have a closer look to what we are facing when using threads and what alternatives we have.
  • 19:00: Session 2: Legacy code refactoring case (Roeland Van Lembergen)
    Going from legacy C++ code to state of the art tested and testable code by means of focused refactoring and componentization. Building a future proof platform using code generation.
  • 19:30: Break
  • 19:45: Session 3: Boost.Asio C++ (Network) Programming (Lieven de Cock)
    Boost.Asio is a cross-platform C++ library for network and low-level I/O programming, either using a synchronous or asynchronous model. We will examine this powerful library in 2 sessions. The first session will first focus on using it as a task processor, something to offload work to, in a nice scaling way with respect to threads. Next we will have a look at timers based upon this library. Equipped with the basic techniques we will start looking at the networking part, first examining some structures and some first network activities, and if time permits it we will implement a first network client. From this talk on boos:asio:ioservice is ready to service you!
    In the second session we will dive head first in the network programming with no further limits.
    Note that the C++ Standard networking proposals are based directly on Boost.Asio, so next to learning this great library we are also preparing for the future C++ standard.
  • 20:45: Experience tour by Barco (Laserprojection/extreme surround sound in new cinema format, operation room for healthcare, control room, entertainment/concerts…), followed by a drink.

The event is free for everyone, but you need to register for it.

There are 100 seats available for this event.

Note: The deadline for registrations is January 5th, 2018!

Share

C++17: Inline Variables

Before C++17, if your class had any non-const static data members, you had to allocate memory for them. For example, suppose you have the following class definition:

class MyClass
{
private:
    static int s_anInt;
    static std::string s_aString;
};

Then your source file should contain the following:

int MyClass::s_anInt = 42;
std::string MyClass::s_aString = "Hello World!";

This is annoying.
C++17 now supports inline variables which allow you to write the MyClass definition as follows:

class MyClass
{
private:
    static inline int s_anInt = 42;
    static inline std::string s_aString = "Hello World!";
};

This feature makes it easier to write header only classes that contain non-const static data members.

At the time of this writing, Microsoft Visual C++ 2017 does not yet support inline variables.

Share

Implementing a Thread-Safe Singleton with C++11 Using Magic Statics

A couple of years ago I wrote a blogpost on how to write a thread-safe singleton using C++11. That implementation used std::call_once().

However, if your compiler is fully C++11 compliant, and by now, all major compilers are fully compliant, then the best way to implement a singleton is to use a magic static, as follows:

class CSingleton final
{
public:
	static CSingleton& GetInstance();

private:
	CSingleton() = default;
	~CSingleton() = default;

	CSingleton(const CSingleton&) = delete;
	CSingleton& operator=(const CSingleton&) = delete;
	CSingleton(CSingleton&&) = delete;
	CSingleton& operator=(CSingleton&&) = delete;
};

CSingleton& CSingleton::GetInstance()
{
	static CSingleton instance;
	return instance;
}

The most important change is the implementation of GetInstance() which now contains a local static variable (magic static). C++11 guarantees that this will be initialized in a thread-safe way.
I have now also marked the class as final, made the destructor non-virtual and private, and deleted the move constructor and move assignment operator.

Share

C++17: Direct vs Copy List Initialization

C++11 introduced the uniform initialization syntax using braced initializer lists. You have direct list initialization which does not include an equal sign, for example:

int myInt{42};

and you have copy list initialization which uses the equal sign, for example:

int myInt = {42};

The auto type deduction rules have changes in C++17. With C++17, if you use copy list initialization, then an initializer_list<> is deduced, for example:

auto initList1 = {42};
auto initList2 = {42, 84, 126};

All values in the braced initializer list must be of the same type. The following does not compile:

auto initList2 = {42, 84.42};

When you use direct list initialization, then a value is deduced. For example, the following deduces an int:

auto anInt{42};

This also means that the following causes a compilation error because more than 1 initialization value is given:

auto ints{42, 84, 126};

This is the new C++17 behavior. With C++11/C++14, all of the above would deduce to an initializer_list<int>.

This changed behavior is included since Microsoft Visual C++ 2015.

Share

C++17: Nested Namespaces

The second post in this series of C++17 features highlights a tiny but very useful new feature called nested namespaces.

Using multi-level namespaces in C++ has always been a pain. Suppose you are writing a game and you have a namespace called Core::Graphics::Rendering. Before C++17 you had to resort to something as follows

namespace Core {
    namespace Graphics {
        namespace Rendering {

            class PostProcessor
            {
            };

        }
    }
}

This leaves you with a very big indentation scheme. You could try to make it look a bit better as follows:

namespace Core { namespace Graphics { namespace Rendering {

    class PostProcessor
    {
    };

}}}

But this does not always plays nice with the auto formatting functionality of your IDE.

Say hello to C++17 nested namespaces. Now you can simply write the following:

namespace Core::Graphics::Rendering {

    class PostProcessor
    {
    };

}

Nested namespaces are supported in Microsoft Visual C++ 2015 since Update 3.

Share

C++17: Structured Bindings

This is a first post in a series of short articles on new C++17 features. These articles will not contain all little details of the new features being presented, but they give you an idea about what new functionality has been added to C++17.

This first article discusses structured bindings. They allow you to declare multiple variables with a single statement that are initialized with values from a pair, tuple, array, or even a struct.

Let’s look at an example using a tuple. Suppose you have the following tuple consisting of a double, string, and integer (note the use of the user-defined std::string literal s):

auto myTuple = std::make_tuple(1.1, "Hello"s, 42);

Before C++17, if you wanted to decompose this tuple into three separate variables, you could use tie() as follows:

double theDouble;
std::string theString;
int theInt;
std::tie(theDouble, theString, theInt) = myTuple;

That’s 4 lines of code just to decompose the tuple.

C++17 structured bindings allow you to do this with a single line:

auto[theDouble, theString, theInt] = myTuple;

It also works for pairs, and this comes in handy for example when using insert() to insert values into a map. insert() returns a pair with as first element an iterator to the inserted element, and as second element a Boolean that is true if the element was inserted successfully. You can decompose that pair as follows:

std::map<int, int> myMap{ {1, 11}, { 2,22 }, { 3,33 }};
auto[it, success] = myMap.insert({ 4,44 });

If you want to use a range-based for loop to iterate over the elements, you could do it as follows:

for (const auto& element : myMap) {
    std::cout << element.first << ": " << element.second << std::endl;
}

The type of the element variable is a pair containing the key and the value of the elements in the map.

Again, you can use structured bindings to make this shorter and easier to understand:

for (const auto&[key, value] : myMap) {
    std::cout << key << ": " << value << std::endl;
}

Structured bindings are available in Microsoft Visual C++ 2017 since Update 3.

Share

Visual Studio 2017 Released

Next BeCPP UG Meeting Planned For April 11th, 2017

The next meeting of the Belgian C++ Users Group is planned for Tuesday April 11th, 2017 at 18:00 at VUB.

SoftKinetic ( https://www.softkinetic.com/ ) is sponsoring this event by providing the location, drinks and catering.

SoftKinetic Logo
The agenda is as follows:

  • 18:00: Sandwiches.
  • 18:30: Session 1: Challenges in Modern Embedded Development Using C++ (Glyn Matthews)
    This talk will cover things such as constrained systems (e.g. CPU, cache, memory), older compilers affecting the use of library and language features from the 2011 standard and beyond, porting, testing etc. One theme will be that what’s “standard” and “modern” is not what you need to get your software working. In some ways, I’d like to push back a bit on the trend to more modern code bases, because it turns out it’s quite rare for developers to have access to the latest language features (and by “latest” I mean 6 years old…)
  • 19:30: Break
  • 19:45: Session 2: SFINAE and type traits: In the Mix (Lieven de Cock)
    The journey will start with a test drive of simple method overloading, shortly later enriched with some ‘templates’ laps. Then we shift gears and we add type traits to the mix. In order to arrive at the finish line, some SFINAE herbs are added to spice up the mix. And as the proof of the pudding is in the eating, a small use case, which will bring things together, will be served.
    In the end the main question remaining is: do we std::enable_if some drinks afterward?
  • 20:45: Short presentation and demo by SoftKinetic followed by a drink.

The event is free for everyone, but you need to register for it.

There are 50 seats available for this event.

Note: The deadline for registrations is April 4th, 2017!

Share