c++17 · ©2017 by it-communication.com 15 c++ c++17: argument deduction for class templates •...

55
©2017 by IT-communication.com 1 C++ Nicolai M. Josuttis 1/17 C++17 ©2017 by IT-communication.com 2 C++ Nicolai M. Josuttis Independent consultant continuously learning since 1962 Systems Architect, Technical Manager finance, manufacturing, automobile, telecommunication Topics: – C++ SOA (Service Oriented Architecture) Technical Project Management Privacy (contributor of Enigmail) Nicolai Josuttis C++17 Copyright 2017 by N. Josuttis. All rights reserved. 1

Upload: duongnhi

Post on 26-Sep-2018

216 views

Category:

Documents


1 download

TRANSCRIPT

©2017 by IT-communication.com 1C++

Nicolai M. Josuttis

1/17

C++17

©2017 by IT-communication.com 2C++

Nicolai M. Josuttis

• Independent consultant– continuously learning since 1962

• Systems Architect, Technical Manager– finance, manufacturing, automobile,

telecommunication

• Topics:– C++– SOA (Service Oriented Architecture)– Technical Project Management– Privacy (contributor of Enigmail)

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 1

©2017 by IT-communication.com 3C++

C++ Timeframe

http://isocpp.org/std/status:

(medium)

©2017 by IT-communication.com 4C++

C++17 Timeframe

http://isocpp.org/std/status

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 2

©2017 by IT-communication.com 5C++

C++11/C++14/C++17 and gcc/g++

• gcc/g++ support of C++11:– some features since 4.3, basic functionality with 4.6– Use -std=c++11 (since 4.7) or -std=c++0x– See https://gcc.gnu.org/projects/cxx-status.html#cxx11

• gcc/g++ support of C++14:– basic functionality with 4.9, full functionality with 5.1– Use -std=c++14 (or -std=c++1y)– See https://gcc.gnu.org/projects/cxx-status.html#cxx14

• gcc/g++ support of C++17:– few features in 6.0, basic functionality with 7.0– Use -std=c++17 (or -std=c++1z)– See https://gcc.gnu.org/projects/cxx-status.html#cxx1z

©2017 by IT-communication.com 6C++

g++/clang Online Compiler

http://melpon.org/wandbox/

uses Server-Side Events (SSE), so your firewall should not blocktext/event-stream

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 3

©2017 by IT-communication.com 7C++

What was not voted into C++17

• Modules• Concepts• Ranges• Co-Routines• Reflection

• Overloading operator.()• Default comparison operators• Uniform Call Syntax• Networking library

– Boost asio

©2017 by IT-communication.com 8C++

General Changes

• C++17 refers to C11 instead of C99

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 4

©2017 by IT-communication.com 9C++

Language Features

C++17

©2017 by IT-communication.com 10C++

C++17: Structured Bindings

• Initialize multiple objects by multiple return values– returned structures– returned tuples– returned arrays

• Types are derived from return valuesstruct MyStruct {

int i;double d;

};MyStruct foo();auto [u,v] = foo(); // u,v have types int,double and are initialized by members of

// of the object returned by foo()

std::tuple<char,float,std::string> g(); auto [a,b,c] = g(); // a,b,c have types char,float,string, initialized by values of returned tuple

int arr[] = { 47, 11 };auto [ x, y ] = arr; // x and y are ints initialized by the elements of arr

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 5

©2017 by IT-communication.com 11C++

C++17: Structured Bindings

• Initialize multiple objects by multiple return values• auto can have the usual qualifiers & and const

auto f() -> int(&)[2]; // return reference to int array

auto [ x, y ] = f(); // x and y have type int and are initialized by the returned arrayauto& [ r, s ] = f(); // r and s refer to elems in the array f's return value refers toconst auto [ a, b ] = f(); // a and b have type const int, initialized by the returned array

std::map<string, double> mymap;...for (auto& [key,val] : mymap) { // access elems key/value by reference

if (key != "ignore") {val *= 2;

}}

for (const auto& [key,val] : mymap) { // access elems key/value by read-only reference std::cout << key << ": " << val << std::endl;

}

©2017 by IT-communication.com 12C++

C++17: Argument Deduction for Class Templates

• Class template parameter types can now be deduced according to arguments passed to the constructor

template <typename T1, typename T2>class D{

public:D (T1 x = T1(), T2 y = T2());...

};

D<std::string, std::string> d0; // OK, T1 and T2 are std::stringD<std::string, std::string> d1("hi","world"); // OK, T1 and T2 are std::string

D d2("hi,"world"); // OK since C++17, T1 and T2 are const char* D d3(22,44.3); // OK since C++17, T1 is int, T2 is double

D d4; // Error: T1 and T2 undefined

std::cout << std::complex(5,3); // OK since C++17, deduces a std::complex<int>std::cout << std::complex(5,3.3); // Error: args do not have the same type

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 6

©2017 by IT-communication.com 13C++

C++17: No Partial Argument Deduction for Class Templates

• Partial class template argument deduction is not possible– Specify all or deduce all template parameters without defaults

template <typename T1, typename T2, typename T3 = T2>class C{

public:C (T1 x = T1(), T2 y = T2(), T3 z = T3());...

};

C<string,string,int> c0; // OK, T1,T2 are string, T3 is intC<string,string,int> c1("hi","guy",42); // OK, T1,T2 are string, T3 is intC<int,string> c2(52,"my"); // OK, T1 is int,T2 and T3 are stringsC<string,string> c3("hi","my","guy"); // OK, T1,T2,T3 are strings C<string,string> c4("hi","my",42); // Error: 42 is not a stringC c5; // Error: T1 and T2 undefinedC c6("hi"); // Error: T2 undefinedC c7(22,44.3); // OK since C++17, T1 is int, T2 and T3 are double C c8(22,44.3,"hi"); // OK since C++17, T1 is int, T2 is double, T3 is const char*C c9("hi","guy"); // OK since C++17, T1, T2, and T3 are const char*C<string> c10("hi","my"); // Error: only T1 explicitly definedC<> c11(22,44.3); // Error: neither T1 not T2 explicitly defined C<> c12(22,44.3,42); // Error: neither T1 not T2 explicitly defined

©2017 by IT-communication.com 14C++

C++17: Applying Argument Deduction for Class Templates

std::cout << std::complex(5,3); // OK since C++17, deduces a std::complex<int>std::cout << std::complex(5,3.3); // Error: args do not have the same type

std::mutex mx;std::lock_guard lg(mx); // OK since C++17, deduces: std::lock_guard<std::mutex>

std::tuple<int> t(42, 43); // still error (good!)

// creating set with specific sorting criterion:std::set<int> coll([](int a, int b) { // still error (too bad)

return a>b;});

std::set<int,std::function<bool(int,int)>> coll([](int a, int b) { // OKreturn a>b;

});

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 7

©2017 by IT-communication.com 15C++

C++17: Argument Deduction for Class Templates

• Class template parameter types can now be deduced according to arguments passed to the constructor

• There are limits/constraints:– make_pair() and make_tuple() are still useful

because they decay– make_shared() and make_unique() are still useful because

class template argument deduction might currently not work there

std::pair p1("hi", "guy"); // Error: can't copy / initialize array parametersauto p2 = std::make_pair("hi","guy"); // OK, creates pair<const char*, const char*>

std::shared_ptr<int> sp1{new int(7)}; // OKstd::shared_ptr sp2{new int(7)}; // Error

namespace std {template<typename T> class shared_ptr {public:

constexpr shared_ptr() noexcept;template<typename Y> explicit shared_ptr(Y* p);...

};}

(can't deduce type T from type Y)

©2017 by IT-communication.com 16C++

C++17: Deduction Guides

• With deduction guides you can guide how to deduce template parameters– Mapping between constructor call and template types

• Must be in the same scope (e.g. namespace std)

// deduction guide: maps shared pointer initialization to shared pointer type:namespace std{

template<typename Y> shared_ptr(Y*) -> shared_ptr<Y>;}

std::shared_ptr<int> sp{new int(42)}; // OKstd::shared_ptr sp{new int(42)}; // OK: deduces: std::shared_ptr<int>std::shared_ptr sp{new int[10]}; // Oops: also deduces: std::shared_ptr<int>

namespace std {template<typename T> class shared_ptr {public:constexpr shared_ptr() noexcept;template<typename Y> explicit shared_ptr(Y* p);...

};}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 8

©2017 by IT-communication.com 17C++

C++17: Deduction Guides

• Several deduction guides @work for C++17

• Deduction guides– must not be templates– must not call a constructor (e.g. also for aggregates)

// map vector initialization with iterators to vector of iterators' element type:namespace std {

template<typename Iterator> vector(Iterator, Iterator)-> vector<typename iterator_traits<Iterator>::value_type>;

}

std::set<double> s;std::vector(s.begin(), s.end()); // deduces std::vector<double>

template <typename T>struct S{

T val;};

S(char const*) -> S<std::string>; // map S with string literals to S<std::string>S s{"hello"}; // same as: S<std::string> s{"hello"};

©2017 by IT-communication.com 18C++

C++17: Explicit Deduction Guides

• Deduction Guides can be explicit– effect as in that case the constructor would be explicit

template <typename T>struct S{

T val;};

explicit S(char const*) -> S<std::string>; // map S with string literals to S<std::string>// (not for implicit construction)

S s{"hello"}; // same as: S<std::string> s{"hello"};

S s = "hello"; // Error

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 9

©2017 by IT-communication.com 19C++

C++17: if and switch with Initializers

• New additional syntax for if and switch:if (init; condition)switch (init; condition)

if (status s = check(); s != SUCCESS) {return s;

}

if (std::lock_guard<std::mutex> lg(mx);!v.empty()) {

std::cout << v.front() << std::endl;}

switch (Foo gadget(args);auto s = gadget.status()) {

case OK: gadget.zip(); break;case Bad: throw BadFoo(s.message());

}

{status s = check();if (s != SUCCESS) { return s;

}}

{std::lock_guard<std::mutex> lg(mv);if (!v.empty()) {std::cout << v.front() << std::endl;

}}

{Foo gadget(args);switch (auto s = gadget.status()) {case OK: gadget.zip(); break;case Bad: throw BadFoo(s.message());

}}

©2017 by IT-communication.com 20C++

C++17: if and switch with Initializers

• Note:– Any temporary in the condition only exists in the initialization,

not in the whole statement • as with for

if (std::lock_guard<std::mutex> lg(mx); !v.empty()) { // OKstd::cout << v.front() << std::endl;

}

if (std::lock_guard<std::mutex> _(mx); !v.empty()) { // OKstd::cout << v.front() << std::endl;

}

if (std::lock_guard<std::mutex>(mx); !v.empty()) { // Error: lock ends before ';'std::cout << v.front() << std::endl;

}

if (std::lock_guard lg(mx); !v.empty()) { // OK, due to class template arg. deductionstd::cout << v.front() << std::endl;

}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 10

©2017 by IT-communication.com 21C++

C++17: Structured Bindings and if with Initializer

• Combining– Initialize multiple objects by multiple return values– New additional syntax for if and switch

• you can replace:

• by:if (auto[pos,done] = coll.insert(42); !done) {

// insert failed, handle error, optionally using posconst auto& [key, val] = *pos;std::cout << "we already have: " << key << std::endl;

}

{auto ret = coll.insert(42);if (!ret.second){

// insert failed, handle error, optionally using ret.firststd::cout << "we already have: " << *(ret.first) << std::endl;

}}

©2017 by IT-communication.com 22C++

Variadic Templates

• Templates for a variable number of template arguments– varargs for templates

• For classes and functions• To process the parameters:

– pass to functions that define specific parameters– may be recursively

void print (){}

template <typename T, typename... Types>void print (const T& firstArg, const Types&... args){

std::cout << firstArg << std::endl;

print(args...);}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 11

©2017 by IT-communication.com 23C++

print ( 7.5, "hello", std::complex(4,2) )

=> print<double> ( 7.5, "hello", std::complex(4,2) )std::cout << 7.5 << std::endl;print ( "hello", std::complex(4,2) )

=> print<const char*> ( "hello", std::complex(4,2) )std::cout << "hello" << std::endl;print ( std::complex(4,2) )

=> print<std::complex> ( std::complex(4,2) )std::cout << std::complex(4,2) << std::endl;print ( )

Variadic Templates

void print (){}

template <typename T, typename... Types>void print (const T& firstArg, const Types&... args ){

std::cout << firstArg << std::endl;

print( args... );

}

©2017 by IT-communication.com 24C++

print ( 7.5, "hello", std::complex(4,2) )

=> print<double> ( 7.5, "hello", std::complex(4,2) )std::cout << 7.5 << std::endl;print ( "hello", std::complex(4,2) )

=> print<const char*> ( "hello", std::complex(4,2) )std::cout << "hello" << std::endl;print ( std::complex(4,2) )

=> print<std::complex> ( std::complex(4,2) )std::cout << std::complex(4,2) << std::endl;print ( )

Variadic Templates

void print (){}

template <typename T, typename... Types>void print (const T& firstArg, const Types&... args ){

std::cout << firstArg << std::endl;

print( args... );

}

Code effectively compiled:

std::cout << 7.5 << std::endl;std::cout << "hello" << std::endl;std::cout << std::complex(4,2) << std::endl;

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 12

©2017 by IT-communication.com 25C++

Dealing with Variadic Templates

• Note that the following code does not work:

• The reason is that for template functions usuallyif any then all code gets instantiated– Results in an error if no print() without any argument is provided

=> To end a recursion over parameter packs,you need another function (until C++17)

template <typename T, typename... Types>void print (const T& firstArg, const Types&... args){

std::cout << firstArg << std::endl;if (sizeof...(args) > 0) {

print(args...); // error if sizeof...(args)==0 and therefor all is an error}

}

©2017 by IT-communication.com 26C++

C++17: Dealing with Variadic Templates: constexpr if

• C++17 provides a compile-time if:

• Disables the compilation of the then/else statement(s) if the condition is always false/true at compile time– "discarded statement"– This might even impact the return type

• Works in both templates and non-templates• Condition must be compile-time evaluable

template <typename T, typename... Types>void print (const T& firstArg, const Types&... args){

std::cout << firstArg << std::endl;if constexpr(sizeof...(args) > 0) {

print(args...);}

}

ignored ifsizeof...(args) <= 0

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 13

©2017 by IT-communication.com 27C++

C++17: constexpr if

• C++17 provides a compile-time if• It also can be used in non-templates

– The discarded statement must be valid,but is not instantiated if it is a template

int main(){

if constexpr(std::numeric_limits<char>::is_signed) {std::cout << "signed: \n";...

}else {

std::cout << "unsigned: \n";...

}}

©2017 by IT-communication.com 28C++

C++17: Fold Expressions

• Apply binary operators to all elements of a parameter pack • Supported syntax:

(... OP pack)(init OP ... OP pack)(pack OP ...)(pack OP ... OP init)

• For operators &&, ||, and , the pack might even be empty– In that case, yields true, false, void()

template <typename... T>auto foldSum (T... s){return (... + s); // s1 + s2 + s3 ...

}

template <typename... Args>void printAllArgs (Args&&... args) {(std::cout << ... << args) << '\n'; // std::cout << args1 << args2 << args3 ... << '\n'

}

Note: no whitespace between args

(( pack1 OP pack2 ) OP pack3 )((( init OP pack1 ) OP pack2 ) OP pack3 )

same from right to left

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 14

©2017 by IT-communication.com 29C++

C++17: Non-Type Template Parameters with auto

• Since C++17 you can declare non-type template parameters with type auto and decltype(auto)

template <auto N> class S {...

};S<42> s1; // OK: type of N in S is intS<'a'> s2; // OK: type of N in S is charS<2.5> s3; // Error: template parameter type still cannot be double

// partial specialization:template <int N> class S<N> {

...};

// template where P must be a pointer to const something:template <const auto* P> struct S;

// List of heterogeneous constant template arguments template <auto... vs> struct value_list { };

// List of homogeneous constant template arguments:template <auto v1, decltype(v1)... vs> struct typed_value_list { };

©2017 by IT-communication.com 30C++

C++17: Inline Variables

• Static variables marked with inline count as definitions– Guaranteed to exist only once in the program

• even if included multiple times in multiple translation units– No need for CPP files to define static/global objects

class C{

private:static inline bool lg = false;

public:static void log (bool b) {

lg = b;}

C() {if (lg) std::cout << "C::C()\n";

}...

};

#include "c.hpp"

int main(){

C::log(true);C c1;...

}

c.hpp:

#include "c.hpp"

void foo(){

C c2;

...}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 15

©2017 by IT-communication.com 31C++

C++17: Inline Variables

• Might be initialized before main() or before first use• constexpr implies inline

class Monitor {public:Monitor() { ... }void log(const std::string& msg) { ... }

};

// Declare THE global monitor in the header file// - might be included by multiple translation unitsinline Monitor globalMonitor;

class WithStaticDataMember {// Since C++17, this is a definition; no further definition in a CPP file is requiredstatic constexpr const char* debug_string = "DEBUG";

};

monitor.hpp:

©2017 by IT-communication.com 32C++

C++17: Aggregates with Base Classes

• Aggregates now can have public base classes• Initialization with nested {} possible

struct CType // existing C type{

uint32_t value;};

struct Derived : CType // C++ type that extends C type{

int status;void f();

};

Derived d1{{42},1}; // OK since C++17, initializes d.value and d.statusDerived d2{{},1}; // OK since C++17, d.value is value initializedDerived d3{}; // Error since C++17

Since C++17, this is an aggregate

might still compile

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 16

©2017 by IT-communication.com 33C++

RValue References and (N)RVO

evaluates as follows:– If class X has an accessible copy or move constructor, the compiler may

choose to elide the copy.– Otherwise, if class X has a move constructor, x is moved.– Otherwise, if class X has a copy constructor, x is copied.– Otherwise, a compile-time error is emitted.

X foo (){

X x;...return x; // NRVO

}

• For rvalue references the rules for (N)RVO (named return value optimization) changed (changes with C++11 in red):

X foo (){

...return X(...); // RVO

}

For RVO,elision is requiredsince C++17

©2017 by IT-communication.com 34C++

C++17: Mandatory Copy Elision

• Copy elision for– initialization from temporaries (prvalues)– returning temporaries (RVO = return value optimization)is now required

• Callable copy/move constructor no longer required

• No required elision for NRVO (returned local objects)

// non-copyable/movable class:class X {

public:X(const X&) = delete;X(X&&) = delete;...

};

X foo (){

...return X(...); // OK since C++17

}

X x = foo(); // OK since C++17

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 17

©2017 by IT-communication.com 35C++

C++14/C++17: New Attributes (Formal Annotations)

• C++14 defines:[[ deprecated ]]– mark names and entities whose use is still allowed, but is discouraged

[[deprecated("use ... instead")]] void gets();

• C++17 defines:[[nodiscard]]– force warning if return values are not used

template <class F, class... Args>[[nodiscard]] future<...> async(F&& f, Args&&... args);

[[ maybe_unused ]]– disabled warnings about names and entities that are intentionally not used– For example:

[[maybe_unused]] int y = foo();

[[ fallthrough ]]– for intentional switch cases having statements but no break;

©2017 by IT-communication.com 36C++

C++17: namespace A::B::C

• New syntax for nested namespaces• Instead of:

you can write since C++17:

namespace A {namespace B {

namespace C {…

}}

}

namespace A::B::C {…

}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 18

©2017 by IT-communication.com 37C++

C++17: Static_assert() without Messages

• static_assert() no longer requires to pass a text message– Printing a default text message if assertion is violated

static_assert(sizeof(int)>=4, "integers are too small"); // OK since C++11static_assert(sizeof(int)>=4); // OK since C++17

template <typename T>class C

{

static_assert(std::is_default_constructible<T>::value,

"class C: element type T must be default-constructible");

static_assert(std::is_default_constructible<T>::value); // OK since C++17...

};

©2017 by IT-communication.com 38C++

Lambda: Capturing this

• In member functions, can also pass this as capture– implicitly done with [=] and [&]

• Since C++17, *this allows to pass *this by value

class C{private:std::string name;

public:...void foo() {

... [] { std::cout << name << std::endl; } ... // Error

... [&] { std::cout << name << std::endl; } ... // OK

... [=] { std::cout << name << std::endl; } ... // OK

... [this] { std::cout << name << std::endl; } ... // OK

... [*this] {std::cout << name << std::endl; } ... // OK since C++17: // creates a local copy of *this

}};

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 19

©2017 by IT-communication.com 39C++

C++17: Heap-Allocation with Alignment

• Since C++17 operator new provides an interface to deal with aligned datatypes

• Several new overloads for operators– new, new[]– delete, delete[]

new T// results into one of (whichever is provided):operator new(sizeof(T))operator new(sizeof(T), std::align_val_t(alignof(T)))

new(adr) std::string// results into one of (whichever is provided):operator new(sizeof(std::string), adr)operator new(sizeof(std::string),

std::align_val_t(alignof(std::string)), adr)

©2017 by IT-communication.com 40C++

C++17: _ _has_include

_ _has_include:

• test for existence of a header• helps to write portable code

• For example:

#if _ _has_include(<optional>)# include <optional># define HAS_OPTIONAL 1#elif _ _has_include(<experimental/optional>)# include <experimental/optional># define HAS_OPTIONAL 1# define OPTIONAL_IS_EXPERIMENTAL 1#else# define HAS_OPTIONAL 0#endif

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 20

©2017 by IT-communication.com 41C++

C++17: Minor other Language Features

• Initialization of enumerations• Expression evaluation order• Lambdas have constexpr support• Range-based for loop support ranges with different begin

and end iterator type (useful for ranges)• Forward progress guarantees• UTF8 character literals: u8'w'• Hexadecimal floating-point literals: 0x3.ABCp-10• noexcept as part of the type system• std::uncaught_exceptions()

©2017 by IT-communication.com 42C++

C++17: std::uncaught_exceptions()

int std::uncaught_exceptions()• Correct interface to detect relevant stack unwinding• Replaces: bool std::uncaught_exception()

– Did not work if object was temporarily created during stack unwindingclass C {

private:int numInitialExceptions;

public:C() : numInitialExceptions(std::uncaught_exceptions()) {}C (const C&) : numInitialExceptions(std::uncaught_exceptions()) {}...~C() {if (numInitialExceptions == std::uncaught_exceptions()) {commit(); // destruction not caused by stack unwinding

}else {rollback(); // destruction caused by stack unwinding

}}

};

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 21

©2017 by IT-communication.com 43C++

C++17: Using std::uncaught_exceptions()

void cleanup(){

C c1("c1");E e1("e1");try {

C c2("c2");E e2("e2");throw "oops";

}catch (...) {}

}

C c("c");D d("d");throw "oops";

C::C() for c: 0 uncaughtD::D() for d--------------------- throwD::~D() for d

C::C() for c1: 1 uncaughtE::E() for e1

C::C() for c2: 1 uncaughtE::E() for e2--------------------- throwE::~E() for e2

C::C() for e2-ctmp: 2 uncaughtC::~C() for e2-ctmp: 2 uncaught => commit()

C::~C() for c2: 2 uncaught => rollback()E::~E() for e1

C::C() for e1-ctmp: 1 uncaughtC::~C() for e1-ctmp: 1 uncaught => commit()

C::~C() for c1: 1 uncaught => commit()C::~C() for c: 1 uncaught => rollback()

class E {private:

std::string name;public:

E(std::string n) : name(n) {}~E() {

C ctmp;}

};

class D {private:

std::string name;public:

D(std::string n) : name(n) {}~D() {

cleanup();}

};

©2017 by IT-communication.com 44C++

C++17: Relaxed Enumeration Initialization

• For enumerations with a fixed underlying type, you can use a value of that type for direct list initializations– applies to both, enum and enum classenum class salutation { mr, mrs };salutation s4 = 0; // Error (all versions)salutation s5(0); // Error (all versions)salutation s6{0}; // OK since C++17 (error before C++17)

enum class Salutation : char { mr, mrs };Salutation s7 = 0; // Error (all versions)Salutation s8(0); // Error (all versions)Salutation s9{0}; // OK since C++17 (error before C++17)

enum salut { mr, mrs };salut s1 = 0; // Error (all versions)salut s2(0); // Error (all versions)salut s3{0}; // Error (all versions)

enum byte : unsigned char { };byte b1 = 42; // Error (all versions)byte b2(42); // Error (all versions) byte b3{42}; // OK since C++17 (error before C++17) byte b4 = {42}; // Error (all versions)

This is, why it was introduced:distinct numeric typesdefined via enum

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 22

©2017 by IT-communication.com 45C++

Enumerations for New Integral Types

• You can use scoped and unscoped enumerations to define new integral types without implicit conversionsenum length_t : std::size_t {}; // new distinct integral type with some restrictions

length_t x; // OKlength_t x1(17); // Errorlength_t x2{17}; // OK since C++17 (error before C++17) length_t x3{-17}; // Error (narrowing)length_t x4 = 17; // Errorlength_t x5 = length_t(17); // OKlength_t x6 = static_cast<length_t>(22); // OK

x = 42; // Errorx = length_t(17); // OKx = x5; // OK

if (x == x5) { // OK

if (x == 17) { // OKint a = x; // OKstd::cout << x + x; // OKx = x + x; // Error

}

all errors with enum class

©2017 by IT-communication.com 46C++

C++17: noexcept is now part of the function type

• C++17 type system differentiates between– noexcept functions– functions that don't guarantee not to throw

• A function that might throw can't be used as noexcept function (the opposite is fine)

• Functions with different specifications what to throw have the same type – Conversions with conflicting throw specifications are possible

void (*p)();void (&r)() noexcept = *p; // Error since C++17 (violates noexcept guarantee)

void (*p)() noexcept;void (&r)() = *p; // OK since C++17

void (*p)() throw(int*);void (&r)() throw(double) = *p; // OK since C++17

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 23

©2017 by IT-communication.com 47C++

C++17: (Bug) Fixes

• Initializer lists and auto• Allow typename instead of class also in template

templates• Allow for all non-type template arguments that are

pointers/references to be arbitrary constant expressions• Allowing attributes such as [[deprecated]] also to apply

on enumerators and namespaces• Inheriting constructors with using now always behaves as

these constructors would be declared again (P0136R0)• Removed:

– Trigraphs– Operator ++ for bool– keyword register (but keep reserved for future use)

©2017 by IT-communication.com 48C++

Initializations auto and {}

• C++11/C++14:int x = 42; // copy initializationint x(42); // direct initialization with C++98/C++03 syntaxint x{42}; // direct list initialization with C++11 syntax

auto x = 42; // copy-initialization, initializes an intauto x{42}; // direct-list-initialization, initializes an initializer_listauto x{1,2}; // direct-list-initialization, initializes an initializer_listauto x = {42}; // copy-list-initialization, initializes an initializer_listauto x = {1,2}; // copy-list-initialization, initializes an initializer_list

• Since C++17, but already in C++11/C++14 compilers:auto x{42}; // direct-list-initialization, initializes an intauto x{1,2}; // errorauto x = {42}; // copy-list-initialization, initializes an initializer_listauto x = {1,2}; // copy-list-initialization, initializes an initializer_list

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 24

©2017 by IT-communication.com 49C++

Vocabulary Types

C++17

©2017 by IT-communication.com 50C++

C++17: std::string_view

• Handle for read-only character sequence– Lifetime of the data not controlled be the object– No allocator support– Passing by value is cheap

• Differs from strings as follows:– Not guaranteed to be null terminated (no NTBS)

• You can place a '\0' as last character, though– Value is nullptr after default construction

• Then: data()==nullptr, size()==0

string:

d a a \0t

string_view:

d a ats o em e m yoi mn r

len:data:

4 len:data:

4

• Always use size()before using the data(operator[],data(),...)

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 25

©2017 by IT-communication.com 51C++

C++17: std::string_view

• Header: <string_view>

• Has some typical string support:– Also: u16string_view, u32string_view, wstring_view– Corresponding literal operator is defined

• Suffix: sv– std::quoted() is supported– Hash values match with hash values of std::string

• Still open integrations:– No regex support

#include <std::literals>

auto s = "some\\value"sv;std::cout << quoted(s); // output: "some\\value"

s:

v a uls o e \\m e \0

len:data:

10

©2017 by IT-communication.com 52C++

C++14: Quoted Strings

• New manipulator std::quoted() to write and read strings with special characters– You can define the delimiter; default: "– You can define the escape character; default: \

...#include <iomanip>

int main(){

std::string s = "\"xml\" with '< > \\ &' is tough";// same as: s = R"("xml" with '< > \ &' is tough)";

std::ofstream out("quoted.tmp");out << std::quoted(s); // writes: "\"xml\" with '< > \\ &' is tough"

std::ifstream in("quoted.tmp");in >> std::quoted(s); // after round trip s has same value again

std::cout << std::quoted(s) << '\n'; // output: "\"xml\" with '< > \\ &' is tough"std::cout << std::quoted(s,'\'','&'); // output: '"xml" with &'< > \ &&&' is tough'

}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 26

©2017 by IT-communication.com 53C++

C++17: std::string_view

• Conversion string => string_view is cheap=> Implicit conversion

• Conversion string_view => string is expensive=> Explicit conversion

void foo_s (const string& s);void foo_v (string_view sv);

foo_s("some value"); // computes length, allocates memory, copies charactersfoo_v("some value"); // computes length only

string: string_view:

v a uls o em e \0

len:data:

10 len:data:

10

v a uls o em e \0

©2017 by IT-communication.com 54C++

C++17: std::string_view

• std::string_view over const std::string&iff:– API doesn't require that string is null terminated

• Not the case when passing to C functions (e.g. fstream => fopen())– Recipient respects lifetime of passed argument– data() access can deal with nullptr

• e.g. check size() before using data()

• Don't return a string_view (unless you know what you do)

• Note: Providing both overloads might cause ambiguitiesvoid foo(const std::string&){

...}void foo(std::string_view){

...}

foo("hello"); // Error: ambiguous

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 27

©2017 by IT-communication.com 55C++

Converting API's from string to string_view

std::string toString (const std::string& prefix,const std::chrono::system_clock::time_point& tp)

{// convert to calendar time:time_t rawtime = std::chrono::system_clock::to_time_t(tp);std::string ts = std::ctime(&rawtime);

ts.resize(ts.size()-1); // skip trailing newline

return prefix + ts;}

std::string toString (std::string_view prefix,const std::chrono::system_clock::time_point& tp)

{// convert to calendar time:time_t rawtime = std::chrono::system_clock::to_time_t(tp);std::string_view ts = std::ctime(&rawtime);

ts.remove_suffix(1); // skip trailing newline

return std::string(prefix) + ts; // unfortunately no operator + yet}

Be careful:Concurrent calls of ctime()or similar functions race

©2017 by IT-communication.com 56C++

New Basic Data Structures

• After pair<>, tuple<>, ...C++17 adds some smart data types to hold a value:

– std::optional<>• optionally holds a value• either empty or has a value of a specific type• adapted from boost:optional<>

– std::variant<>• holds a value that might have one of multiple pre-defined types• usually never empty (only due to some exceptions)• differs from boost:variant<>

– std::any<>• holds a value that might have any possible type• may be empty• adapted from boost::any<>

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 28

©2017 by IT-communication.com 57C++

C++17: std::optional<>

• Structure to optionally hold a value of a certain type– either empty or has a value– no need to deal with special values such as NULL or -1

• Adapted from boost::optional– std::nullopt instead of boost::none

std::optional<std::string> empty;std::optional<std::string> optStr("hello");optStr = "new value";*optStr = "new value";...if (optStr) { // equivalent to: if (optStr.has_value())std::string s = *optStr; // undefined behavior if no value

}

try {std::string s = optStr.value(); // exception if no value

}catch (const std::bad_optional_access& e) {optStr.reset(); // makes it empty

}

©2017 by IT-communication.com 58C++

C++17: Example for std::optional<>

#include <optional>#include <string>#include <iostream>

std::optional<std::string> foo() // returns string (may be empty) or "no string"{

static int numCalls = 0;++numCalls;

switch (numCalls%3) {case 0:

return std::nullopt; // returns no string; same as: return std::optional<std::string>{}case 1:

return ""; // returns string that is emptycase 2:

return std::to_string(numCalls); // returns non-empty string}

}

int main(){

for (int i=0; i < 20; ++i) {const std::optional<std::string>& s = foo();if (s)

std::cout << "foo() returned '" << *s << "'\n"; // string (may be empty)else

std::cout << "foo() returned nothing" << std::endl; // no string}

}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 29

©2017 by IT-communication.com 59C++

C++17: std::variant<>

• Structure to hold a value of one of the specified "alternatives"– Multiple occurrences of identical types are allowed

• Interface with index like tuple– Default-Constructible if first "alternative" is default constructible

• Can use std::monostate to have such a type

• Differs from boost::variant#include <variant>

std::variant<int, std::string> var(42); // => var.index() == 0var = "new value"; // => var.index() == 1...try {std::string s = std::get<std::string>(var); // access by typeint i = std::get<0>(var); // access by index

}catch (const std::bad_variant_access& e) { // if type or index currently not used}

©2017 by IT-communication.com 60C++

C++17: std::variant<> Error Handling

#include <variant>

std::variant<int, int, std::string> var; // sets first int to 0, index()==0 var = "hello"; // sets string, index()==2var.emplace<1>(42); // sets second int, index()==1

try {auto s = std::get<std::string>(var); // throws exception (second int currently set)auto a = std::get<double>(var); // compile-time error: no doubleauto b = std::get<4>(var); // compile-time error: no 4th alternativeauto c = std::get<int>(var); // compile-time error: int twiceauto i = std::get<1>(var); // OK, i1==42auto j = std::get<0>(var); // throws exception (other int currently set)

std::get<1>(var) = 77; // OK, because second int already set std::get<0>(var) = 99; // throws exception (other int currently set)

}catch (const std::bad_variant_access& e) { // if runtime error

std::cout << "Exception: " << e.what() << std::endl;}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 30

©2017 by IT-communication.com 61C++

C++17: std::variant<> Becoming Empty

• variant<> might become empty only by unhandled exception– Only if using the variant after exception without re-initialization

• Then:valueless_by_exception() == trueindex() == std::variant_npos

struct S {operator int() { throw "EXCEPTION"; } // any conversion to int throws

};

std::variant<float,int> var{12.2};try {var.emplace<1>(S()); // oops, throws while being set

}catch (...) {

// oops, really don't set var to a new defined state?}// var.valueless_by_exception() == true// var.index() == std::variant_npos

©2017 by IT-communication.com 62C++

C++17: std::variant<> Visitors

std::variant<int, std::string> var(42);...

struct MyVisitor{

void operator()(double d) const {std::cout << d << '\n';

}void operator()(int i) const {std::cout << i << '\n';

}void operator()(std::string s) const {std::cout << s << '\n';

}};std::visit(MyVisitor(), var); // compile-time error if not all possible types supported

// or with ambiguities

std::visit([](auto&& val) { // call lambda for the appropriate typestd::cout << val << '\n';

},var);

• Using visitors:

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 31

©2017 by IT-communication.com 63C++

C++17: std::variant<> Visitors

struct MyVisitor {template <typename T> // visitor for single value of any typevoid operator()(T& var) {std::cout << var;

}void operator()(int i, double d, char c) { // for specific 3 values

std::cout << i << ' ' << d << ' ' << c;}void operator()(...) { // for all other cases

std::cout << "no match";}

};std::variant<int, std::string> var1{12};std::variant<std::string, double> var2{13};std::variant<std::string, char> var3{'x'};std::visit(MyVisitor(), var1, var2, var3); // prints: 12 13.0 xvar2 = "hello";std::visit(MyVisitor(), var1, var2, var3); // prints: no matchstd::visit(MyVisitor(), var2); // prints: hello

• Multi-Visitors

©2017 by IT-communication.com 64C++

C++17: std:any

• Type to hold any possible value of any type– may be empty

• Adapted from boost::anystd::any empty;std::any anyVal(42);anyVal = std::string("hello");anyVal = "oops"; // Beware: type is const char*, so stores the address...if (anyVal.has_value()) { // 'if (anyVal)' not supportedif (anyVal.type() == typeid(std::string)) { // 'type()==typeid(void)' if empty

std::string s = std::any_cast<std::string>(anyVal);}

}

try {int i = std::any_cast<int>(anyVal); // type must match exactly (only const/refs ignored)

}catch (std::bad_any_cast&) {anyVal.reset(); // makes it empty

}

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 32

©2017 by IT-communication.com 65C++

C++17: Move Semantics with std:any

• Types in std::any must be copyable– Move-only types are not supported

• But you can use move semantics

std::string s("a pretty long string value (disabling SSO)");std::cout << "s: " << s << std::endl; // outputs the initialized string

std::any a;a = std::move(s); // move s into astd::cout << "s: " << s << std::endl; // probably outputs an empty string...s = std::any_cast<std::string>(std::move(a)); // move string in a into sstd::cout << "s: " << s << std::endl; // outputs the original string

©2017 by IT-communication.com 66C++

Library Features

C++17

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 33

©2017 by IT-communication.com 67C++

C++17: Filesystem Library

• C++ API to deal with files, directories, paths, ...• Adapted from boost

• Modifications:– Root elements are not longer filenames– A path ending with / no longer yields "." as last element

• Extensions:– Relative path functions

• can compute– lexically (just according to syntax)– operational (according to the file system (e.g. resolving symbolic links))– operational as long as possible

• with and without absolute path as fallback

©2017 by IT-communication.com 68C++

C++17: Filesystem: Simple Example#include <iostream>#include <filesystem>

int main (int argc, char* argv[]){

if (argc < 2) {std::cout << "Usage: " << argv[0] << " <path> \n";return EXIT_FAILURE;

}

std::filesystem::path p(argv[1]); // p represents a filesystem path (might or might not exist)if (exists(p)) { // does path p actually exist?

if (is_regular_file(p)) { // is path p a regular file?std::cout << " size of " << p << " is " << file_size(p) << '\n';

}else if (is_directory(p)) { // is path p a directory?

std::cout << p << " is a directory containing:\n";for (auto& e : std::filesystem::directory_iterator(p)) { // e is directory_entry

std::cout << " " << e.path() << '\n'; }

}else {

std::cout << p << " exists, but is neither a regular file nor a directory\n";}

}else {

std::cout << "path " << p << " does not exist\n";}

}

No change from boost API, except header file and namespace

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 34

©2017 by IT-communication.com 69C++

C++17: Filesystem: Modifying Example#include <iostream>#include <fstream>#include <filesystem>

int main (){

try {std::filesystem::path tmpDir("/tmp");std::filesystem::path testPath = tmpDir / "test";if (!create_directory(testPath)) {

std::cout << "test directory already exists" << std::endl;}

create_symlink(testPath, std::filesystem::path("myTestData.txt"));

testPath /= "data.txt";std::ofstream dataFile(testPath.string());if (dataFile) {

dataFile << "start of data:\n";}

}catch (std::filesystem::filesystem_error& e) {

std::cout << "error creating test directory " << e.path1()<< ": " << e.what() << std::endl;

}}

No change from boost API, except header file and namespace

©2017 by IT-communication.com 70C++

filenamestem + extfilename

stem + extfilename

stem + extfilename

stem + extfilename

stem + extfilename

stem + extension

Terminology: Elements of a Path

• Terms:– Root-Name: //host or C: or ...– Root-Directory: same as directory separator– Directory-Separator: / or \ or // or \\ ...

• multiple separators are interpreted as one

dirsepar.

rootname

rootdir

dirsepar.

C: \ foo \ bar \ file . txt

//host / foo / bar / file . txt

dirsepar.

rootname

rootdir.

directoryseparator

extension (from last "." til end)

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 35

©2017 by IT-communication.com 71C++

C++17: Filesystem: Modifying Example#include <iostream>#include <filesystem>using namespace std;using namespace std::filesystem;

int main (){

path p0 = path("foo") / "bar";cout << p0 << '\n';

path p("/foo/bar/data.txt");cout << p << '\n';p.make_preferred();cout << p << '\n';

cout << "decomposition:\n";cout << p.root_name() << '\n';cout << p.root_directory() << '\n';cout << p.root_path() << '\n';cout << p.relative_path() << '\n';cout << p.parent_path() << '\n';cout << p.filename() << '\n';cout << p.stem() << '\n';cout << p.extension() << '\n'; cout << p.is_absolute() << '\n';

}

"foo/bar" "foo\bar"

"""/""/""foo/bar/data.txt""/foo/bar""data.txt""data"".txt"1 (true)

"""\""\""foo\bar\data.txt""\foo\bar""data.txt""data"".txt"0 (false)

"/foo/bar/data.txt"

"/foo/bar/data.txt"

"/foo/bar/data.txt"

"\foo\bar\data.txt"

Windows:Unix:

©2017 by IT-communication.com 72C++

Filename Changes for C++17

• Filenames starting with . are no extensions

• Filename is what is between root or directory separators– Root elements are no filenames

• has_filename() is no longer true for "//host" or under Windows: "C:"– Paths with trailing / have no filenames

• has_filename() is no longer true for "foo/"– Always: filename() == stem() "+" extension()

• When iterating over a path, the empty stringrepresents a trailing non-root directory separator– We can now distinguish between root-dir, trailing /, and "." in paths

• Loops of remove_filename() no longer unwind a path– use iterators and/or loops over parent_path()

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 36

©2017 by IT-communication.com 73C++

Clarify filename() for C++17

oldfilename()

oldstem()

"." "." "."".." ".." "..""/foo/bar.txt" "bar.txt" "bar""/foo/bar" "bar" "bar""/foo/bar/.git" ".git" """/foo/bar/." "." ".""/foo/bar/" "." ".""/" "/" "/""//host" "//host" "//host""//host/" "/" "/""C:" "C:" "C:" or """C:/" "." or "/" "." or "/""C:foo/" "." ".""C:." "C:." or "." "C:" or ".""" "" ""

or: Unix vs. Windows• Remember: In Unix "C:" is nothing special

©2017 by IT-communication.com 74C++

Clarify filename() for C++17

oldfilename()

oldstem()

C++17filename()

C++17has_filename()

C++17stem()

C++17extension()

"." "." "." "." true "." """.." ".." ".." ".." true ".." """/foo/bar.txt" "bar.txt" "bar" "bar.txt" true "bar" ".txt""/foo/bar" "bar" "bar" "bar" true "bar" """/foo/bar/.git" ".git" "" ".git" true ".git" """/foo/bar/." "." "." "." true "." """/foo/bar/" "." "." "" false "" """/" "/" "/" "" false "" """//host" "//host" "//host" "" false "" """//host/" "/" "/" "" false "" """C:" "C:" "C:" or "" "C:" or "" true or false "C:" or "" """C:/" "." or "/" "." or "/" "" false "" """C:foo/" "." "." "" false "" """C:." "C:." or "." "C:" or "." "C:." or "." true "C:" or "." "." or """" "" "" "" false "" ""

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 37

©2017 by IT-communication.com 75C++

Relative Path Function

• But:– Should we normalize (remove redundant path elements):

• "sub/../sub/." => "sub" ?– How to deal with symbolic links

• Should we follow symbolic links?• Then "sub/../sub" is not always "sub"

– How to deal with "." and ".."– Paths may or may not exist yet

• which we may or may not want to consider– What if there is no common root:

• Relative path from "C:\a" to "D:\b" ?– ...

// simple example:std::filesystem::path p("/a/b/c");std::filesystem::path base("/a/b");std::filesystem::path rel = std::relative(p, base); // the requested functionstd::cout << rel << std::endl; // outputs: "c"assert(std::absolute(rel, base) == p);

©2017 by IT-communication.com 76C++

Examples with Symbolic Links

Note some command-line shells lie:• After cd a/d/e

• I am in a/b• But shells claim I am in a/d/c

• ls ../e is not an error• cd ../e is not an error

• Try: pwd –P and cd –P

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 38

©2017 by IT-communication.com 77C++

Relative Path Function

• Prefix lexically_ to ignore existing file system– assume there are no symbolic links– cheap

• relative() and lexically_relative()– return relative path (empty if none)

• proximate() and lexically_proximate()– return relative path (absolute path if none)

• lexically_normal()– to normalize a path

• weakly_canonical()– resolve symlinks as long as files exist and then normalize lexically

©2017 by IT-communication.com 78C++

C++17: Parallel Execution of STL Algorithms

• Execution of STL algorithms in parallel• Adopted from Parallel TS (see N4352)• Different execution policies:

• Current implementations:– Microsoft: http://parallelstl.codeplex.com– HPX: http://stellar-group.github.io/hpx/docs/html/hpx/manual/parallel.html– Codeplay: http://github.com/KhronosGroup/SyclParallelSTL– HSA: http://www.hsafoundation.com/hsa-for-math-science– Thibaut Lutz: http://github.com/t-lutz/ParallelSTL– NVIDIA: http://github.com/n3554/n3554

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 39

©2017 by IT-communication.com 79C++

C++17: Parallel Execution Policies

Parallelsequencedexecution:

c

a

b

c

a

b

c

a

b

c

a

b

c

a

b

c

a

b

c

a

b

c

a

b

c

a

b

Parallelunsequencedexecution:

Sequentialexecution:

• Multiple threads might execute tasks• Threads might execute parts of other

tasks before ending the first task� Don't lock on the same mutex� No memory (de)allocation

• Multiple threads might execute tasks• Tasks are processed sequenced from

begin to end� All steps must be able to be done

concurrently

• One thread executes all tasks, one after the other

• Sequenced from begin to end

©2017 by IT-communication.com 80C++

C++17: When to use which Parallel Execution Policy?

transform (std::execution::par_unseq,coll1.begin(),coll1.end(), // source rangecoll2.begin(), // destination range[] (auto x) { // operation

auto y = x * x; // OK, for each element the only requirement isreturn y; // OK, to keep the order of statements

});

transform (std::execution::par,coll1.begin(),coll1.end(), // source rangecoll2.begin(), // destination range[] (auto x) { // operation

std::lock_guard<mutex> lg(m); // OK for par but not for par_unseqreturn x*x;

});

transform (std::execution::seq,coll1.begin(),coll1.end(), // source rangecoll2.begin(), // destination range[] (auto x) { // operation

logFile << x; // concurrent access to files is a racereturn x*x;

});

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 40

©2017 by IT-communication.com 81C++

C++17: Splicing Sets and Maps with Node Handles

• Interface and type to splice elements (nodes) between (unordered) sets and maps– Better performance than remove() and insert()– to splice only key/value types (and allocator) have to match

• comparison criterion, hash function, ... might differ • from container without duplicates to corresponding container with

duplicates is supported (e.g. set <-> multiset)

• Type for "node handle" is container::node_type– value() for all set types– key() and mapped() for all map types– move semantics

©2017 by IT-communication.com 82C++

C++17: Examples for Splicing Sets and Maps with Node Handles

// Moving elements from one map to another:std::map<double, std::string> src {{1.1,"one"}, {2.2,"two"}, {3.3,"three"}};std::map<double, std::string> dst {{3.3,"old data"}}; dst.insert(src.extract(src.find(1.1))); // splice using an iterator dst.insert(src.extract(2.2)); // splice using the key auto r = dst.insert(src.extract(3.3)); // extracts but doesn't insert // state:// src == {} // dst == {{1.1,"one"}, {2.2,"two"}, {3.3,"old data"}}// r.position == next(next(dst.begin()))// r.inserted == false // r.node.key() == 3.3// r.node.mapped() == "three"

// Move elems into a set and move them out:std::set<MoveOnlyType> s; s.insert(MoveOnlyType(...));s.emplace(...);MoveOnlyType m = std::move(s.extract(s.begin()).value());

// move necessary because value() yields non-const lvalue reference

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 41

©2017 by IT-communication.com 83C++

C++17: Examples for Splicing Sets and Maps with Node Handles

// Failing to find an element to removestd::multiset<int> src{1, 1, 3, 5}; std::set<int> dst; dst.insert(src.extract(1)); // OK, splices first element with value 1 auto r = dst.insert(src.extract(2)); // extract() fails, so that insert() fails// state:// src == {1, 3, 5} // dst == {1}// r.position == src.end()// r.inserted == false // r.node.empty() == true// r.node.value() // Error: undefined behavior (e.g. segmentation fault)

// Changing the key of a map element:std::map<int, std::string> m{{1,"mango"}, {2,"papaya"}, {3,"guava"}}; auto nh = m.extract(2);nh.key() = 4; m.insert(std::move(nh)); // Error without move()// state:// m == {{1,"mango"}, {3,"guava"}, {4,"papaya"}}

©2017 by IT-communication.com 84C++

C++17: Elementary String Conversions

to_chars(beg,end, 44) // decimalto_chars(beg,end, 44, 16) // hexadecimal to_chars(beg,end, 44, 13) // to the base of 13 (base between [2,36])

to_chars(beg,end, 44.1234567) // decimal, roundtrip-able, %f or %e acc. to minimal # chars

to_chars(beg,end, 44.1234567, chars_format::general) // decimal, %g, roundtrip-ableto_chars(beg,end, 44.1234567, chars_format::fixed) // decimal, %f, roundtrip-ableto_chars(beg,end, 44.1234567, chars_format::scientific) // decimal, %e, roundtrip-ableto_chars(beg,end, 44.1234567, chars_format::hex) // hex, %a, roundtrip-able

to_chars(beg,end, 44.1234567, chars_format::general, 4) // decimal, %g, precision: 4to_chars(beg,end, 44.1234567, chars_format::fixed, 4) // decimal, %f, precision: 4to_chars(beg,end, 44.1234567, chars_format::scientific, 4) // decimal, %e, precision: 4to_chars(beg,end, 44.1234567, chars_format::hex, 4) // hex, %a, precision: 4

• Low-level C++ API for printf()-like formatting– simple, fast, locale-independent

• Including round-trip support

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 42

©2017 by IT-communication.com 85C++

C++14/C++17: Shared Locks

• To support Read/Write Locks (RW locks)– C++14 introduces

• Class std::shared_timed_mutex• Class std::shared_lock<>

– C++17 introduces• Class std::shared_mutex

• Allows to share a lock for multiple concurrent reads– No reader or writer preference defined (quality of implementation)

• Generic approach:– Use existing lock interfaces for exclusive locks– Use additional interfaces for shared locks

• special state, available only in shared mutexes

std::shared_mutex sm;...{

std::shared_lock<std::shared_mutex> sharedLock(sm); // calls sm.lock_shared()...

} // sm.unlock_shared() called here

©2017 by IT-communication.com 86C++

atomic<> Operations

• To check whether a type is natively atomic:– Preprocessor constants (taken from C):

#define ATOMIC_BOOL_LOCK_FREE unspecified#define ATOMIC_CHAR_LOCK_FREE unspecified#define ATOMIC_INT_LOCK_FREE unspecified#define ATOMIC_LONG_LOCK_FREE unspecified#define ATOMIC_LLONG_LOCK_FREE unspecified#define ATOMIC_POINTER_LOCK_FREE unspecified...

• might yield 0 for never, 1 for sometimes, 2 for always lock-free– Member function is_lock_free()

• yields true if the object has native atomic support, so that it doesn't use locks– N2427: The proposal provides lock-free query functions on individual objects

rather than whole types to permit unavoidably misaligned atomic variables without penalizing the performance of aligned atomic variables.

• Note that atomic<int> differs from int even if it is lock free, because it introduces memory barriers.

C++17 will add:constexpr boolatomic<T>::is_always_lock_free

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 43

©2017 by IT-communication.com 87C++

C++14: More Convenience for Type Traits returning Types

• In C++14, shortcuts are provided for type traits,returning types

• Instead of:typename std::remove_const<T>::type

you can use:std::remove_const_t<T>

• This is done via Alias Templates:namespace std {

template <typename T>using remove_const_t = typename remove_const<T>::type;

}

typename remove_const<T>::type tmp; // since C++11 remove_const_t<T> tmp; // since C++14

©2017 by IT-communication.com 88C++

C++14: Variable Templates

• Ability to define simple generic variables/objects/references/members– can have default template parameters– can be partially specialized– can't be overloaded

template <typename T>T pi{3.1415926535897932385};

std::cout << pi<double> << std::endl;

template <typename T = long double>constexpr T pi = T(3.1415926535897932385);

std::cout << pi<> << std::endl; // OKstd::cout << pi << std::endl; // error

Note:"Variable Template"� "Variadic Template"

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 44

©2017 by IT-communication.com 89C++

C++17: More Convenience for Type Traits returning Values

• In C++17, shortcuts will be provided for type traits,returning values

• Instead of:std::is_const<T>::value

you can use:std::is_const_v<T>

• This is done via Variable Templates:namespace std {

template <typename T>constexpr bool is_const_v = is_const<T>::value;

}

if (is_const<T>::value) // since C++11 if (is_const_v<T>) // since C++17

©2017 by IT-communication.com 90C++

Overloading Templates and Non-Templates

• Templates match better than implicit conversions

void print (long obj){

std::cout << "print(long):" << obj << std::endl;}

template <typename T>void print (T obj){

std::cout << "print<>(T): " << obj << std::endl;}

print(100L); // calls print(long)print(42); // calls print<int>(T) (better match)print(8u); // calls print<unsigned int>(T) (better match)print("hello"); // calls print<const char[6]>(T)print(7.3); // calls print<double>(T)

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 45

©2017 by IT-communication.com 91C++

enable_if<>

• Disable template code acc. to compile-time expression– Code is ignored due to SFINAE ("SFINAE'd out")

• Placeable wherever a type is used

void print (long obj){

std::cout << "print(long):" << obj << "\n";}

template <typename T>typename std::enable_if< !std::is_integral<T>::value >::typeprint (T obj){

std::cout << "print<>(T): " << obj << "\n";}

print(100L); // calls print(long)print(42); // calls print(long)print(8u); // calls print(long)print("hello"); // calls print<const char[6]>(T)print(7.3); // calls print<double>(T)

• void if condition is true at compile time

• all ignored if not

©2017 by IT-communication.com 92C++

enable_if<>

• Disable template code acc. to compile-time expression– Code is ignored due to SFINAE ("SFINAE'd out")

• Placeable wherever a type is used

void print (long obj){

std::cout << "print(long):" << obj << "\n";}

template <typename T>typename std::enable_if< !std::is_integral<T>::value >::typeprint (T obj){

std::cout << "print<>(T): " << obj << "\n";}

print(100L); // calls print(long)print(42); // calls print(long)print(8u); // calls print(long)print("hello"); // calls print<const char[6]>(T)print(7.3); // calls print<double>(T)

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 46

©2017 by IT-communication.com 93C++

enable_if<>

• Disable template code acc. to compile-time expression– Code is ignored due to SFINAE ("SFINAE'd out")

• Placeable wherever a type is used

void print (long obj){

std::cout << "print(long):" << obj << "\n";}

template <typename T>voidprint (T obj){

std::cout << "print<>(T): " << obj << "\n";}

print(100L); // calls print(long)print(42); // calls print(long)print(8u); // calls print(long)print("hello"); // calls print<const char[6]>(T)print(7.3); // calls print<double>(T)

©2017 by IT-communication.com 94C++

enable_if<> since C++14

• Disable template code acc. to compile-time expression– Code is ignored due to SFINAE ("SFINAE'd out")

• Placeable wherever a type is used

void print (long obj){

std::cout << "print(long):" << obj << "\n";}

template <typename T>std::enable_if_t< !std::is_integral<T>::value > // void or all ignoredprint (T obj){

std::cout << "print<>(T): " << obj << "\n";}

print(100L); // calls print(long)print(42); // calls print(long)print(8u); // calls print(long)print("hello"); // calls print<const char[6]>(T)print(7.3); // calls print<double>(T)

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 47

©2017 by IT-communication.com 95C++

enable_if<> since C++17

• Disable template code acc. to compile-time expression– Code is ignored due to SFINAE ("SFINAE'd out")

• Placeable wherever a type is used

void print (long obj){

std::cout << "print(long):" << obj << "\n";}

template <typename T>std::enable_if_t< !std::is_integral_v<T> > // void or all ignoredprint (T obj){

std::cout << "print<>(T): " << obj << "\n";}

print(100L); // calls print(long)print(42); // calls print(long)print(8u); // calls print(long)print("hello"); // calls print<const char[6]>(T)print(7.3); // calls print<double>(T)

©2017 by IT-communication.com 96C++

C++17: New Numeric Library Features

• Special math functions added from C added:– elliptic integrals, polynomials, Bessel functions, ...

• add gcd() and lcm()– templates for all integral types (also char) except bool

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 48

©2017 by IT-communication.com 97C++

C++17: Minor other Library Features

• std::string got non-const data() member• shared_ptr<C[]> and shared_ptr<C[2]>

– no support for shared_from_this• will always throw, because it is never initialized

• Shared pointers now provide weak_type• New search algorithms:

– "Boyer-Moore" and "Boyer-Moore-Horspool"• More support for memory resource management

– memory_resource, polymorphic_allocator, pool resource classes,– see Section 20.12

• Portable way to access the L1 data cache line size – hardware_constructive_interference_size, hardware_destructive_interference_size

• New type traits– is_callable– has_unique_object_representations

• to find out whether equal objects have equal hash values

©2017 by IT-communication.com 98C++

C++17: (Bug) Fixes

• Guarantee that shared_from_this() throws bad_weak_ptr if no shared pointer was created for an object yet

• Let emplace functions return a reference to what they inserted– Before C++17, return type was void

• Undefined behavior for type traits now is an error• Temporarily discourage memory_order_consume• Remove the constructors taking allocators from

std::function• Adding constexpr in a lot of places• ...

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 49

©2017 by IT-communication.com 99C++

C++14 Features

Modern C++

©2017 by IT-communication.com 100C++

C++14: New Numeric Literals

• C++14 allows to– define binary literals– use digit separators

• Can be placed anywhere between two digits of a literal

int x = 10'000'000; // 10 millionint y = 10'00'00'00; // 10 milliondouble z = 0.000'000'001; // 1 billionth (nano)

int a1 = 42; // decimal 42int a2 = 0x2A; // hexadecimal 42int a3 = 052; // octal 42int a4 = 0b101010; // binary 42

int f = 0b1111'1111; // binary 255

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 50

©2017 by IT-communication.com 101C++

C++14: Return-Type auto

• Since C++14, you can skip the trailing return type, if it can be deduced from the code– Types of multiple return statements must match– Even possible for recursive functions

auto add (int x, int y) // return type int deduced{if (x < y) {

return x + y;}return 0;

}

// define foo() with return type of c.begin() for passed constant c:template <typename C>auto foo (const C& c) -> decltype(c.begin()){

...return c.begin();

}

©2017 by IT-communication.com 102C++

int i = 42; // i has type intconst auto& ref = i; // ref has type const int& and refers to i

auto v1 = ref; // v1 has type int and is a new independent object

decltype(auto) v2 = ref; // v2 has type const int& and also refers to i

template <typename T>decltype(auto) callFoo(T x) // return whatever foo() returns (reference or value){return foo(x);

}

C++14: decltype(auto)

• While auto deduces types– ignoring references, const, and volatile

• decltype(auto)– deduces types as they are– Declared objects may be a value or may be a reference

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 51

©2017 by IT-communication.com 103C++

auto vs. auto&& vs. decltype(auto)

auto never is a referenceauto&, auto&& always is a referencedecltype(auto) sometimes is a reference

Type s;

... = s;

const Type cs;

... = cs;

Type s;Type& rs(s);

... = rs; ... = Type();

Type s;

... = std::move(s);

auto a = ... Type Type Type Type Type

auto& a = ... Type& const Type& Type& invalid invalid

const auto& a = ... const Type& const Type& const Type& const Type& const Type&

auto&& a = ... Type& const Type& Type& Type&& Type&&

decltype(auto) a = ... Type const Type Type& Type Type&&C++14:

©2017 by IT-communication.com 104C++

C++14: Standard Class Specific Literals

C++14 adds standard literals:• For std::string

– Suffixes: s (applied to C-string literals)– Literal shall not use memory when std::string_ref is added

• For std::duration– Suffixes: h, min, s, ms, us, ns (applied to numeric literals)– no problem with suffix s because the literal is initialized with different

• For std::complex– Suffixes: i, il, if (applied to numeric literals)

• With careful namespace design:– To use literals together with the types:

using namespace std;

– To use all literals without qualification: using namespace std::literals;

– To use literals operators for a specific type without qualification:using namespace std::string_literals;

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 52

©2017 by IT-communication.com 105C++

C++14: Using Standard Literals

• Note: no space between value and literal

using namespace std::literals;

// define and pass an std::string:auto s = "myfile"s + suffix;auto t = "hello" s; // errorcheck("myfile.cpp"s);

// wait for 10 seconds:std::this_thread::sleep_for(10s);

// define complex<double>(10,3):auto val = 10 + 3i;

©2017 by IT-communication.com 106C++

C++14: "Making Operator Functors greater<>"

• C++14 makes the usage of less<>, greater<>, etc.easier by not requiring to specify the element type– see http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2014/n3932.htm

std::set<std::string,std::greater<std::string> > coll1; // OK since C++98

std::set<std::string,std::greater<std::string>> coll2; // OK since C++11

std::set<std::string,std::greater<>> coll3; // OK since C++14

std::vector<std::string> v1;std::sort(v1.begin(), v1.end(), std::greater<>()); // OK since C++14

std::vector<std::string> v2;auto pos = std::find_if (v2.begin(), v2.end(),

std::bind(std::greater<>(), // OK since C++14std::placeholders::_1,"A"));

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 53

©2017 by IT-communication.com 107C++

C++14: Generic Lambdas

• C++14 introduces lambdas that are templates– Using auto (not template)– The usual template deduction rules apply

• That is:

has the effect of:

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

};

class unnamed_lambda {public:unnamed_lambda () = delete; // initial constructor only callable by compilertemplate <typename T1, typename T2>auto operator() (T1 x, T2 y) const {return x + y;

}};auto lambda = unnamed_lambda();

©2017 by IT-communication.com 108C++

C++14: Example for Generic Lambdas

// print all elements of any kind:std::for_each (coll.begin(), coll.end(),

[] (const auto& elem) {std::cout << elem << std::endl;

});

// define a generic lambda object:auto sum = [] (auto x) {

return x+x;};

// and call/use it:auto i = sum(3); // i is int => 6auto d = sum(1.7); // d is double => 3.4auto s = sum(std::string("hello")); // s is std::string => "hellohello"auto s = sum("hello"); // Error: const char* + const char*

// replace all elements of coll by the sum with themselves:std::transform (coll.begin(), coll.end(), // source range

coll.begin(), // destination rangesum); // transformation

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 54

©2017 by IT-communication.com 109C++

Q&A, Contact

Nicolai M. Josuttis

[email protected]

Nicolai Josuttis C++17

Copyright 2017 by N. Josuttis. All rights reserved. 55