C++17- More Details about the Core Language

Contents[Show]

After I provided the big picture to the new C++17 core language in my post "C++17 - What's New in the Core Language", I will give you more details today. The details are mainly about inline variables, templates, automatic type deduction with auto, and attributes.

Here is the big picture of C++17 once more.

timeline

But let me write about the not so well-known feature.

Inline variables

Thanks to inline variables, the main reason to not packaging C++ code as header-only libraries are gone. You can declare global variables and static variables inline. The same rules that are applied to inline functions are applied to inline variables.

That means:

  • There can be more than one definitions of an inline variable.
  • The definition of an inline variable must be present in the translation unit, in which it is used.
  • A global inline variable (non-static inline variable) must be declared inline in every translation unit and has the same address in every translation unit.

Once more, the great benefit of inline variables. You can put your variables directly into you header files and include them more than once.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// widget.h

class Widget{
  public:
    Widget() = default;
    Widget(int w): width(w), height(getHeight(w)){}
    Widget(int w, int h): width(w), height(h){}

  private:
    int getHeight(int w){ return w*3/4; }
    static inline int width= 640;
    static inline int height= 480;
    static inline bool frame= false;
    static inline bool visible= true;

    ...
};

inline Widget wVGA;

 

auto can automatically deduce the type of its variable from its initialiser. The story with auto goes on. Thanks to auto, template parameters of function templates and constructors (see C++17 - What's New in the Core Language) can automatically be deduced from its arguments, and non-type template parameters can automatically be deduced from it template arguments. Irritate about the last part of my sentence? Irritated? That's fine. I will write about the last part of my sentence in the next chapter.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Stay informed about my mentoring programs.

 

 

Subscribe via E-Mail.

Automatic type deduction of non-type template parameters

First of all. What are non-type template parameters? These are nullptr, integral, lvalue reference, pointer, and enumeration types. I will refer in this post mainly to integral types.

After so much theory, let's start with an example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
template <auto N>
class MyClass{
  ...
};

template <int N> 
class MyClass<N> {
  ...
};


MyClass<'x'> myClass2;     // Primary template for char
MyClass<2017>  myClass1;   // Partial specialisation for int

 

By using auto in line 1 in the template signature,  N is a non-type template parameter. The compiler will automatically deduce it. A partial specialisation for int is also possible: lines 6 and 7. The template instantiation in line 12 will use the primary template (line 1-4) and the following template instantiation the partial specialisation for int.

The usual type modifiers can be used to constrain the type of the non-type template parameters. Therefore, you don't have to use partial specialisation.

template <const auto* p> 
struct S;

Here, p must be a pointer to const.

The automatic type deduction for non-type template parameters works even for variadic templates.

1
2
3
4
5
6
7
8
9
template <auto... ns>
class VariadicTemplate{
  ...
};

template <auto n1, decltype(n1)... ns>
class TypedVariadicTemplate{
  ...
};

 

Therefore, VariadicTemplate in lines 1-4 can deduce an arbitrary number of non-type template parameters. TypeVariadicTemplate will deduce only the first template parameter. The remaining templated parameters will be of the same type.

The rules for auto in combination with a {}-Initialisation change in C++17.

auto in combination with an {}-Initialisation

If you use auto in combination with an {}-Initialisation, you will get a std::initializer_list.

  auto initA{1};          // std::initializer_list<int>
  auto initB= {2};        // std::initializer_list<int>
  auto initC{1, 2};       // std::initializer_list<int>
  auto initD= {1, 2};     // std::initializer_list<int>

 

That was an easy to remember and to teach rule. Sad to say, however, C++17 make the feature from my perspective not better.

  auto initA{1};          // int
  auto initB= {2};        // std::initializer_list<int>
  auto initC{1, 2};       // error, no single element
  auto initD= {1, 2};     // std::initializer_list<int>

 

Now, the rule is more complicated. Assigning with a {} returns a std::initializer_list. Copy construction only works for a single value.

Now to a small, but nice feature.

Nested namespaces

With C++17, you can quite comfortable define nested namespaces.

Instead of writing

namespace A {
  namespace B {
    namespace C {
      ...
    }
  }
}

you can simply write:

namespace A::B::C {
  ...
}

 

C++17 has the three new attributes [[fallthrough]], [[nodiscard]], and [[maybe_unused]].

The three new attributes fallthrough, nodiscard, and maybe_unused

All three deal with compiler warnings. The examples are from cppreference.com.

fallthrough

[[fallthrough]] can be used in a switch statement. It has to be on its own line, immediately before a case label and indicates that a fall through is intentional and should therefore not diagnose a compiler warning.

Here is a small example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
void f(int n) {
  void g(), h(), i();
  switch (n) {
    case 1:
    case 2:
      g();
     [[fallthrough]];
    case 3: // no warning on fallthrough
      h();
    case 4: // compiler may warn on fallthrough
      i();
      [[fallthrough]]; // ill­formed, not before a case label
  }
}

 

The [[fallthrough]] attribute in line 7 suppresses a compiler warning. That will not hold for line 10. The compiler may warn. Line 12 is ill-formed because no case label is following.

nodiscard

[[nodiscard]] can be used in a function declaration, enumeration declaration, or class declaration. If you discard the return value from a function declared as nodiscard, the compiler should issue a warning. The same holds for a function returning an enumeration or a class, declared as nodiscard. A cast to void should not emit a warning.

Therefore, line 5 should emit a warning but line 10 should not produce a warning because the function foo returns by reference.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
struct [[nodiscard]] error_info { };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
   enable_missile_safety_mode(); // compiler may warn on discarding a nodiscard value
   launch_missiles();
}
error_info& foo();
void f1() {
    foo(); // nodiscard type is not returned by value, no warning
} 

maybe_unused

[[maybe_unused]] can be used in the declaration of a class, a typedef­, a variable, a non­-static data member, a function, an enumeration, or an enumerator. Thanks to maybe_unused, the compiler suppresses a warning on an unused entity. 

 

1
2
3
4
5
6
void f([[maybe_unused]] bool thing1,
       [[maybe_unused]] bool thing2)
{
   [[maybe_unused]] bool b = thing1;
   assert(b); // in release mode, assert is compiled out
}

 

In release mode, line 5 is compiled out. That should produce no warning because b is declared as maybe_unused. The same holds for the variable thing2.

What's next?

After my introduction to the core C++17 language ( C++17 - What's New in the Core Language), I gave you in this post more details. The same will hold for my next post. I will present in my next post more details to the new C++17 library. So, in case C++17 - What´s New in the Library made you curious.

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Dominik Vošček, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

Mentoring

Stay Informed about my Mentoring

 

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 1504

Yesterday 4791

Week 1504

Month 191580

All 11672734

Currently are 200 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments