pecos c++ sessions: modern c++roystgnr/modern_cxx-talk.pdfsome language features are optional or...

95
PECOS Predictive Engineering and Computational Sciences PECOS C++ Sessions: Modern C++ Roy Stogner Center for Predictive Engineering and Computational Sciences (PECOS) Institute for Computational Engineering and Sciences (ICES) The University of Texas at Austin May 10, 2017 Roy Stogner Modern C++ May 10, 2017 1 / 59

Upload: others

Post on 22-May-2020

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

PECOSPredictive Engineering and Computational Sciences

PECOS C++ Sessions: Modern C++

Roy Stogner

Center for Predictive Engineering and Computational Sciences (PECOS)Institute for Computational Engineering and Sciences (ICES)

The University of Texas at Austin

May 10, 2017

Roy Stogner Modern C++ May 10, 2017 1 / 59

Page 2: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

What is “Modern” C++?• 1979 C With Classes (CFront ”compiler”)• 1983 C++: virtual functions, operator overloading• 1985 The C++ Programming Language• 1989 Multiple inheritance, protected, static members• 1990 Turbo C++ compiler• 1993 Exceptions• 1998 C++98: STL standardized• 2003 C++03: “bugfix” standard• 2005 “C++0x”/“TR1”: smart pointers, PRNGs, regex, C99,

hash-based containers, array, tuple• 2011 C++11: move, constexpr, initializer lists, type inference, range

for, lambda, constructor delegation, variadic templates, threads• 2014 C++14: return type deduction, relaxed constexpr, auto lambdas• 2017? C++1z: if/switch initializers, if constexpr, constructor template

deduction, non-member size() empty() data(), fold expressions, ??

Roy Stogner Modern C++ May 10, 2017 2 / 59

Page 3: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compiler SupportSome language features are optional or belatedly supported:• C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

I/O manipulators, optional garbage collection• C++11: without optional garbage collection• C++14-lite: without avoiding/fusing memory allocations• C++1z-lite: without map/set splices, new string conversions• Intel: when paired with sufficiently advanced libstdc++

C++11-lite C++11 C++14-lite C++14 C++1z-liteGCC 4.8.1 (2013) 5.1 5.1 (2016) 5.0 7 (May 2)Clang 3.3 (2013) 3.8 3.4 (2014) 3.4 SVNIntel 15.0 (2014) 17.0 (2016)PGI 2015MSVC 2015• C++11 is barely supported by most (Red Hat Enterprise Linux 6

based) scientific computing cluster• C++14 is barely supported if you build your whole software stack.

Roy Stogner Modern C++ May 10, 2017 3 / 59

Page 4: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Why use Modern C++?Brevity:• Lambda (anonymous) functions instead of heavy functor classes• Initialization lists for container construction• Range loops vs iterators, dereferencing• Alias templates vs typedefs• Much easier metaprogramming• Default member initialization

Safety:• More smart pointer options to reduce leaks, dangling pointers• nullptr, override, final to catch overloading mistakes• Compile-time static assert

Efficiency:• Move construction to reduce copies• Compile-time metaprogramming vs runtime

Roy Stogner Modern C++ May 10, 2017 4 / 59

Page 5: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Default Member Initializationint counter = 0;class Foo {public:

Foo() {assert(bar == 3 && baz == "4");

}Foo(int new_qux) : qux(new_qux) {

assert(bar == 3 && baz == "4" &&qux == new_qux);

}private:

int bar = 3;std::string baz = "4";int qux = counter++;

}

• Each new default-constructed Foo records its order of creation

• Using the new qux constructor doesn’t increment the counter

Roy Stogner Modern C++ May 10, 2017 5 / 59

Page 6: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform Initialization

“Most vexing parse”:

int i = 0; // Constructs iint i2(0); // Sameint i3(); // Declares a function!

Uncopyable objects are more finicky:

std::atomic<int> a(0); // Constructs astd::atomic<int> a = 0; // Syntax error!

Brace syntax now works for everything:

int i3{}; // Default-constructs i3std::atomic<int> a{0}; // Just fine!int i4 = {0}; // "=" is allowed but meaningless

Roy Stogner Modern C++ May 10, 2017 6 / 59

Page 7: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform vs Aggregate InitializationC++98 aggregate initialization works only on aggregates:// no user-declared constructor, private/protected members,// base class(es), virtual functionsstruct MyAggieStruct {

int x; double y;};

class MyClass {private: // Non-aggregate!

int x; double y;public:

ClassB(int _x, double _y):x(_x),y(_y) {} // Non-aggregate!};

MyAggieStruct s = {1, 2.0}; // C-style struct arguments// MyClass c = {1, 2.0}; // Syntax error with classes!

C++11 brace syntax still works for everything:MyAggieStruct s = {1, 2.0}; // Great!MyClass c = {1, 2.0}; // Also great!

Roy Stogner Modern C++ May 10, 2017 7 / 59

Page 8: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform Initialization via listsC++98 container construction:

const int a[] = {3, 1, 4, 1, 5}; // Easy!std::vector<int> v; // Not with vectorv.push_back(3); // Fill itv.push_back(1); // Keep filling itv.push_back(4); // Man, you thought it was annoyingv.push_back(1); // to include iostream and declarev.push_back(5); // main just to print "Hello World"?

• Even const containers end up declared non-const

• Memory allocation is questionable

• Different containers’ insert methods differ

• What happened to array initialization?

With C++11 initializer lists:

const std::vector<int> v = {3, 1, 4, 1, 5}; // Great!

Roy Stogner Modern C++ May 10, 2017 8 / 59

Page 9: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform Initialization via nested lists

C++98 nested container construction:

std::map<std::string, std::string> phones;phones["Jenny"] = "867-5309";phones["Kramer"] = "555-FILK";phones["Mr. Plow"] = "KL5-3226";

• Does default initialization, then overwrites with assignment

With C++11 initializer lists

const std::map<std::string, std::string> phones ={ {"Jenny", "867-5309"},{"Kramer", "555-FILK"},{"Kramer", "KL5-3226"} };

Roy Stogner Modern C++ May 10, 2017 9 / 59

Page 10: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform Initialization via nested lists

Each internally-nested list gets passed to the appropriate internalinitializer list constructor, or to the autogenerated constructor foraggregates, or to the best matching old-style constructor.

const std::tuple<std::string, MyAggieStruct, MyClass> stuff=

{ "junk", {1, std::exp(1.0)}, {2, std::exp(2.0)} };

This is safer than non-brace initialization, because narrowing conversionslike int i = 2.5; are prohibited

• If MyAggieStruct or MyClass was using float or int and wehanded it double, the compiler would catch our mistake

We can now do in-place construction of essentially any wild combination ofC++ classes, with no way for it to go wrong!

On the next several slides: several horrible ways for it to go wrong.

Roy Stogner Modern C++ May 10, 2017 10 / 59

Page 11: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform Initialization via nested lists

Each internally-nested list gets passed to the appropriate internalinitializer list constructor, or to the autogenerated constructor foraggregates, or to the best matching old-style constructor.

const std::tuple<std::string, MyAggieStruct, MyClass> stuff=

{ "junk", {1, std::exp(1.0)}, {2, std::exp(2.0)} };

This is safer than non-brace initialization, because narrowing conversionslike int i = 2.5; are prohibited

• If MyAggieStruct or MyClass was using float or int and wehanded it double, the compiler would catch our mistake

We can now do in-place construction of essentially any wild combination ofC++ classes, with no way for it to go wrong!

On the next several slides: several horrible ways for it to go wrong.

Roy Stogner Modern C++ May 10, 2017 10 / 59

Page 12: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Uniform Initialization ambiguity

With C++11 initializer lists:

const std::vector<int> v {3, 1, 4, 1, 5}; // Still great!const std::vector<int> v2{3, 1}; // Leading subset of vconst std::vector<int> v3(3, 1); // NOT equal to v2

• vector has existing constructor options:I One-argument: countI Two-argument: count, valueI Two-argument: begin, end input iteratorsI Allocator object options

• Reinterpreting initializer list construction hides all these

Be aware of the distinction, and use the appropriate initialization forobjects where the interpretation differs.

Roy Stogner Modern C++ May 10, 2017 11 / 59

Page 13: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

User initializer list constructorsLike templates, using a class with well-designed initializer listconstructors is easy, but properly creating such a class can be hard. Why?It’s easy to define:

// Constructor delegationMatrix(std::initializer_list<std::initializer_list<T>> lst) :Matrix(lst.size(), lst.size() ? lst.begin()->size() : 0){

int i = 0, j = 0;// Range for, auto type deductionfor (const auto& l : lst) {

for (const auto& v : l) {data[i + j * row] = v;++j;

}j = 0;++i;

}}

Roy Stogner Modern C++ May 10, 2017 12 / 59

Page 14: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

User initializer list constructorsEasy to define, but also easy to break other constructors, because if any“matching” initializer list constructor exists, it is preferred overany non-list constructor in override resolution:

class Meta {public:

Meta(int i, long double l);Meta(std::initializer_list<double> il);

operator float() const;...

};

Meta m2{10, 5.0L}; // Error! initializer_list "matches" but// with narrowing-conversion

Meta m{10, 5}; // Creates initializer_list: int// widening-conversion to double

Meta m2{m}; // Creates initializer_list: w user-conversion// to float, widening-conversion to double

Roy Stogner Modern C++ May 10, 2017 13 / 59

Page 15: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

User initializer list constructors

Resolutions?

• If you offer one initializer list constructor, you had betterhandle all the things which might be thrown at it

• Implicit conversion operators remain extremely dangerous

• Generic code must explicitly decide (and document!) what type ofinitialization it performs on template types.

Roy Stogner Modern C++ May 10, 2017 14 / 59

Page 16: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

nullptr: now actually a pointerIn C++98, overloading on integer and pointer types is always advisedagainst, and could be disastrous:

void f(int);void f(long);void f(void*);

f(NULL); // Might not compile, if decltype(NULL) is long// Might call f(int), if decltype(NULL) is int// Will *never* call f(void*)

In C++11, that’s still good advice, but if some idiot ignored it, you’re safer:

void f(int);void f(long);void f(void*);

f(nullptr); // Always calls f(void*)

nullptr is of type nullptr t, which converts to any pointer type andto nothing else.

Roy Stogner Modern C++ May 10, 2017 15 / 59

Page 17: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

alias templatesC++11 alias declarations are slightly easier to read than typedefs forfunction pointers:

typedef void (*FP)(int, const std::string&);

using FP = void (*)(int, const std::string&);

And alias template declarations are much easier to read than templatemetafunctions:

template<typename T>struct MyAllocList {typedef std::list<T, MyAllocT> > type;

};typename MyAllocList<T>::type mylist;

template <typename T>using MyAllocList = std::list<T, MyAlloc<T>>;MyAllocList<T> mylist;

Roy Stogner Modern C++ May 10, 2017 16 / 59

Page 18: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Explicit override declarations

C++98 run-time error:

class BaseClass {public:

virtual void evaluate();virtual void set_param(int p = 0);virtual void is_homogeneous() { return false; }void initialize();

};

class HomoSubclass {public:virtual void evaluate() const;virtual void set_param(double p = 0);virtual void is_homogenous() { return true; }virtual void initialize();

};

Roy Stogner Modern C++ May 10, 2017 17 / 59

Page 19: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Explicit override declarationsC++11 adds override as a “contextual keyword”: still usable as anidentifier (so you don’t have to change your code if it had an “override”variable or function), but now meaningful as language keywords in theright context (at the end of a member function declaration):

class BaseClass {public:virtual void evaluate();virtual void set_param(int p = 0);virtual void is_homogeneous() { return false; }

};

class HomoSubclass {public:virtual void evaluate() const override;virtual void set_param(double p = 0) override;virtual void is_homogenous() { return true; } override;

};

Turns run-time into compile-time errorsRoy Stogner Modern C++ May 10, 2017 18 / 59

Page 20: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Explicit final declarations

Another contextual keyword: final

class BaseClass {public:virtual double operator()(unsigned int i) const;

};

class HomoSubclass {public:virtual double operator()(unsigned int i) const final{ return _data[_lookup[i]]; }

};

• final method calls can be de-virtualizedI Even for interprocedural objects

• final method calls can be inlined

• A final class can prevent subclassing entirely!

Roy Stogner Modern C++ May 10, 2017 19 / 59

Page 21: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant expressionsC++98 compile-time calculations have the semantics of a functionallanguage, with the syntax of a language designed by accident:

template <int N>struct Factorial {static const int value = N * Factorial<N-1>::value;

};

template <>struct Factorial<0> {static const int value = 1;

};

unsigned int twentyfour = Factorial<4>::value;

• This code requires 0 FLOPS at run time!

• And is hideous!• And is allowed to break at compile time by the C++ standard!

I Compile with -ftemplate-depth-1337 if you need 1337 levels oftemplate recursion with GCC

Roy Stogner Modern C++ May 10, 2017 20 / 59

Page 22: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant expressionsC++98 compile-time calculations have the semantics of a functionallanguage, with the syntax of a language designed by accident:

template <int N>struct Factorial {static const int value = N * Factorial<N-1>::value;

};

template <>struct Factorial<0> {static const int value = 1;

};

unsigned int twentyfour = Factorial<4>::value;

• This code requires 0 FLOPS at run time!• And is hideous!

• And is allowed to break at compile time by the C++ standard!

I Compile with -ftemplate-depth-1337 if you need 1337 levels oftemplate recursion with GCC

Roy Stogner Modern C++ May 10, 2017 20 / 59

Page 23: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant expressionsC++98 compile-time calculations have the semantics of a functionallanguage, with the syntax of a language designed by accident:

template <int N>struct Factorial {static const int value = N * Factorial<N-1>::value;

};

template <>struct Factorial<0> {static const int value = 1;

};

unsigned int twentyfour = Factorial<4>::value;

• This code requires 0 FLOPS at run time!• And is hideous!• And is allowed to break at compile time by the C++ standard!

I Compile with -ftemplate-depth-1337 if you need 1337 levels oftemplate recursion with GCC

Roy Stogner Modern C++ May 10, 2017 20 / 59

Page 24: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant expressionsC++98 compile-time calculations have the semantics of a functionallanguage, with the syntax of a language designed by accident:

template <int N>struct Factorial {static const int value = N * Factorial<N-1>::value;

};

template <>struct Factorial<0> {static const int value = 1;

};

unsigned int twentyfour = Factorial<4>::value;

• This code requires 0 FLOPS at run time!• And is hideous!• And is allowed to break at compile time by the C++ standard!

I Compile with -ftemplate-depth-1337 if you need 1337 levels oftemplate recursion with GCC

Roy Stogner Modern C++ May 10, 2017 20 / 59

Page 25: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant expressions

C++11 compile-time calculations look like C++, restricted to functionalprogramming semantics:

constexpr int factorial (int N) {return N <= 1 ? 1 : (N * factorial(N-1));

}

C++14 compile-time calculations can look like C++

constexpr int factorial (int N) {int returnval = 1;for (int i=2; i <= N; ++i)returnval *= i;

return returnval;}

Roy Stogner Modern C++ May 10, 2017 21 / 59

Page 26: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant types

constexpr expressions must work with “literal types”, any one of:

• Built-in scalar types

• References to literal types

• Arrays of literal types

• Const/volatile qualified versions of literal types• Classes, if restricted to:

I Have a trivial destructorI Aggregate types or types with at least one constexpr constructor

(aside from copy and move constructors)I Have non-volatile literal types for all non-static data members and base

classes• (or at least for one member, in C++17 unions)

• void, in C++17

Roy Stogner Modern C++ May 10, 2017 22 / 59

Page 27: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time constant functionsconstexpr functions must be evaluable at compile time:• Return value must be a literal type• Every parameter must a literal type• Can only have one “real” statement, the return statement, in C++11• Must not be virtual• Must not construct a class with virtual base classes• Must be evaluated only as a “core constant expression”:

I No calls to non-constexpr functions or constructorsI No evaluations which might be undefined behavior

• (e.g. taking the address of a constant; dividing by zero)I No lambda expressions (until C++17)I No RTTI, reinterpret castI No modification of objects outside the expressionI No exception throwing or catching

Even so, constexpr calculation is *still* allowed to break at compile timeby the C++ standard!• Compile with -fconstexpr-depth-1337 if you need 1337 levels

of constexpr recursion with GCCRoy Stogner Modern C++ May 10, 2017 23 / 59

Page 28: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Compile-time assertions

Given a constexpr, whether a declared function or a local expression,we can assert a compile-time error if it is false!

static_assert(dependent_false<T>::value,"Only specializations of StandardType "" may be used, did you forget to ""include a header file (e.g. ""parallel_algebra.h)?");

static_assert(Attributes<T>::has_min_max,"Tried to verify an unverifiable type");

static_assert(sizeof(PetscInt) == sizeof(numeric_index_type),"PETSc and libMesh integer sizes must match!");

• Static assertions are practically free!

Roy Stogner Modern C++ May 10, 2017 24 / 59

Page 29: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

New smart pointers: unique ptr

Solves the same problems as auto ptr:• Annotating and enforcing proper deletion

I ”Do I delete?”I ”How do I delete?”I ”When do I delete?”I ”How do I delete if an exception is thrown?”

• Determining whether a pointer is dangling

But also solves the problems of auto ptr:

• Usable as pointer-to-array

• Usable in containers, via move construction• Unusable via copy construction

I (rather than unleashing pure evil via copy construction)

Roy Stogner Modern C++ May 10, 2017 25 / 59

Page 30: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

New smart pointers: shared ptr, weak ptr

An attempt to combine the ease of garbage collection with thepredictability of explicit destruction:

• shared ptr objects are heap-constructed (oruser-allocator-constructed)

• shared ptr maintains a reference count for the allocated object

• Creating a new shared ptr atomically increments the referencecount

• Destructing a shared ptr atomically decrements the referencecount

• Destructing the last shared ptr destroys the object

Roy Stogner Modern C++ May 10, 2017 26 / 59

Page 31: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

New smart pointers: shared ptr

Like auto ptr and unique ptr, a shared ptr:

• Can have a custom deleter

Like unique ptr, a shared ptr:• Can be safely stored in containers

I Efficiently, thanks to move semantics!

But unique ptr, like raw pointer, can outperform and can be moreflexible than shared ptr, which:

• Requires a heap-allocated “control block” (reference count, weakcount, custom deleter pointer... typically 24 bytes) per object

• Requires a member pointer to the control block (typically 8 bytes) perpointer

• Requires atomic operations on the reference count

• Cannot be moved into another unique ptr

Roy Stogner Modern C++ May 10, 2017 27 / 59

Page 32: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

New smart pointers: weak ptrA.k.a. “a shared ptr that can dangle”.Initialize a weak pointer from a shared pointer:

std::shared_ptr<Foo> spf(new Foo());std::weak_ptr<Foo> wpf(spf);

Later, check if the object still exists:

if (wpf.expired()) std::cout << "Expired!";

Or, use the object iff it still exists, in one of two atomic (thread-safe!) ways:

// Get a shared pointer which is null if wpf expiredstd::shared_ptr<Foo> spf2 = wpf.lock();

// Throw std::bad_weak_ptr if wpf expiredstd::shared_ptr<Foo> spf2(wpf);

weak ptr allows cycles of pointers without memory leaks, whereas if Ahas a shared ptr to B which has a shared ptr to A, neither will everbe deleted

Roy Stogner Modern C++ May 10, 2017 28 / 59

Page 33: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

make sharedC++11 make shared gives slightly less repetitive code:

std::shared_ptr<FooBar> pf(new FooBar(arg));auto pf(std::make_shared<FooBar>(arg));

But also can prevent memory leaks from exceptions!

processFoo(std::shared_ptr<FooBar>(new FooBar(arg)),riskyfunc());

Will the compiler call new FooBar, then shared ptr::shared ptr,then riskyfunc()?• All is well: any exception thrown by riskyfunc() will unwind and

destruct the FooBar.

Will the compiler call new FooBar, then riskyfunc(), thenshared ptr::shared ptr?• The C++ (and C!) standards allow that level of reordering• All is not well: any exception thrown by riskyfunc() will leave a

FooBar undestructed and unreachableRoy Stogner Modern C++ May 10, 2017 29 / 59

Page 34: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

make uniqueC++14 make unique does the same for unique ptr:

std::unique_ptr<FooBar> pf(new FooBar(arg));auto pf(std::make_unique<FooBar>(arg));

This is missing from C++11, but can be reimplemented there easily.

(For some definition of easily):

template <typename T, typename... Ts>std::unique_ptr<T> make_unique(Ts&&... params){return std::unique_ptr<T>

(new T(std::forward<Ts>(params)...));}

We’ll discuss this after I explain variadic arguments, variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences, which will be shortly after I understand variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences.

Roy Stogner Modern C++ May 10, 2017 30 / 59

Page 35: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

make uniqueC++14 make unique does the same for unique ptr:

std::unique_ptr<FooBar> pf(new FooBar(arg));auto pf(std::make_unique<FooBar>(arg));

This is missing from C++11, but can be reimplemented there easily.(For some definition of easily):

template <typename T, typename... Ts>std::unique_ptr<T> make_unique(Ts&&... params){return std::unique_ptr<T>

(new T(std::forward<Ts>(params)...));}

We’ll discuss this after I explain variadic arguments, variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences, which will be shortly after I understand variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences.

Roy Stogner Modern C++ May 10, 2017 30 / 59

Page 36: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

make uniqueC++14 make unique does the same for unique ptr:

std::unique_ptr<FooBar> pf(new FooBar(arg));auto pf(std::make_unique<FooBar>(arg));

This is missing from C++11, but can be reimplemented there easily.(For some definition of easily):

template <typename T, typename... Ts>std::unique_ptr<T> make_unique(Ts&&... params){return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));

}

We’ll discuss this after I explain variadic arguments, variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences, which will be shortly after I understand variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences.

Roy Stogner Modern C++ May 10, 2017 30 / 59

Page 37: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

make uniqueC++14 make unique does the same for unique ptr:

std::unique_ptr<FooBar> pf(new FooBar(arg));auto pf(std::make_unique<FooBar>(arg));

This is missing from C++11, but can be reimplemented there easily.(For some definition of easily):

template <typename T, typename... Ts>std::unique_ptr<T> make_unique(Ts&&... params){return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));

}

We’ll discuss this after I explain variadic arguments, variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences, which will be shortly after I understand variadic templates,parameter packs, perfect forwarding, rvalue references, and universalreferences.

Roy Stogner Modern C++ May 10, 2017 30 / 59

Page 38: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

pImplpImpl (“pointer to implementation”) idiom:

class Lorem { // Declarations in Lorem.hpublic:Lorem(); // Definition in Lorem.C, does new Impl˜Lorem(); // Definition in Lorem.C, does delete Impl...

private:class LoremImpl; // Forward declarationLoremImpl *pImpl;

};

• Removes LoremImpl code, header dependencies from Lorem.hI No Impl usage possible in inline methods

• Forward declarations of normal member types are useful for this evenwithout a special Impl class

• “Owned” members then need heap allocation, manual new/delete inthe owning class constructor/destructor

Roy Stogner Modern C++ May 10, 2017 31 / 59

Page 39: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

pImpl and unique ptrpImpl idiom with smart pointers:

class Lorem { // Declarations in Lorem.hpublic:Lorem(); // Definition in Lorem.C, does make_unique˜Lorem(); // Definition in Lorem.C...

private:class LoremImpl; // Forward declarationstd::unique_ptr<LoremImpl> pImpl;

};

• Constructor uses make unique for allocation• Destructor deallocation is now automatic• Shallow copy construction is now not automatic• Constructor and destructor still should be declared manually, and

defined (even if empty or = default) in Lorem.C!I Automatic destructor generation will fail anywhere the Impl class is an

incomplete type!

Roy Stogner Modern C++ May 10, 2017 32 / 59

Page 40: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 41: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 42: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 43: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings

• Non-generic: code depends on random access, container size()method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 44: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 45: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 46: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?

• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 47: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: indexingWhat is wrong with this?

for (int i=0; i != vec.size(); ++i)do_something(vec[i]);

• Infinite loop with 32-bit int and vec.size() > 232

• Repeated vec.size() loads if do something() doesn’t get completeinlining and/or Inter-Procedural Optimization

• signed/unsigned comparison warnings• Non-generic: code depends on random access, container size()

method

What about this?

for (std::size_t i=0; i != vec.size(); ++i)do_something(vec[i]);

• Optimizer can no longer rely on undefined overflow!?• Still non-generic

Roy Stogner Modern C++ May 10, 2017 33 / 59

Page 48: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 49: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays

• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 50: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 51: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 52: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!

• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 53: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 54: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.

Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 55: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Bad for loops: pointers, iteratorsCan we use pointers C-style?

for (int * p = vec; p != vec + vec_size; ++p)do_something(*p);

• Only works with C arrays• Slightly harder to read loop contents

What’s wrong with this non-array pointer version?const int * end = &vec[0] + vec.size();for (int * p = &vec[0]; p != end; ++p)do_something(*p);

• Now it only works with C++-style vectors!• Undefined (horrible) behavior on empty vectors

const T::const_iterator end = container.end();for (T::iterator it = container.begin(); it != end; ++it)do_something(*it);

• Fine, that’s as good as it gets.Roy Stogner Modern C++ May 10, 2017 34 / 59

Page 56: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Range-based for loops

for ( range_declaration : range_expression ) loop_statement

Expands to the right thing in most cases in C++11:

{auto && __range = range_expression ;for (auto __begin = begin_expr, __end = end_expr;__begin != __end; ++__begin) {range_declaration = *__begin;loop_statement}

}

• {begin expr, end expr} are whatever they should be!I { range, range + bound} for a C-style array of known sizeI { range.begin(), range.end()} if those members existI {begin( range), end( range)} if those functions can be

found with Argument-Dependent Lookup

Roy Stogner Modern C++ May 10, 2017 35 / 59

Page 57: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Range-based for loops

for ( range_declaration : range_expression ) loop_statement

Expands to the right thing in all cases in C++17:

{auto && __range = range_expression ;auto __begin = begin_expr ;auto __end = end_expr ;for ( ; __begin != __end; ++__begin) {range_declaration = *__begin;loop_statement}

}

• {begin expr, end expr} can be different types if required forweirdness/efficiency.

Roy Stogner Modern C++ May 10, 2017 36 / 59

Page 58: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Range-based for loop examplesstd::vector<int> v = {0, 1, 2, 3, 4, 5};

for (const int& i : v) // explicit const referencedo_something(i);

for (auto i : v) // deduced type is intdo_something(i);

for (auto&& i : v) // deduced type is int&do_something(i);

for (int n : {0, 1, 2, 3, 4, 5}) // braced rangesdo_something(n);

int a[] = {0, 1, 2, 3, 4, 5};for (int n : a) // array ranges

do_something(n);

for (int n : a)do_something(1); // unused variables okay

Roy Stogner Modern C++ May 10, 2017 37 / 59

Page 59: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Value types: lvalues vs rvaluesAn “lvalue” expression in C (and C++98, etc) was so named because itcan be thought of as a “left-hand-side” value of an assignment:• my lvalue = something

An “rvalue” (“right hand side” value) is anything else, such as a non-stringliteral or a temporary.• A better rule of thumb: it’s sane to take addresses of lvalues, but not

of rvalues.I &myvar makes senseI &(myvar + 42) is nonsense

• Same expression type, but different value category!I &myarray[5] makes sense if not OOBI &42 is nonsenseI &f(myvar) makes sense iff f returns a reference

• But you can take const references to rvalues:I const int & myref = 2 + 2; is allowed

• Lots of lvalues can’t actually be the left-hand side of an assignment:I myvar = foo fails for const typesI myvar = foo fails for types without assignment operatorsRoy Stogner Modern C++ May 10, 2017 38 / 59

Page 60: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

C++11 rvaluesIn C and C++03, an rvalue can be thought of as “a value that is about togo away”.• If you don’t take a reference to the object created by an rvalue

expression, it gets destroyed at the end of the expressionI If you do take a reference, the object gets destroyed at the end of the

reference’s scope; this isn’t garbage collection.

• This is why passing a temporary to a function by non-const referenceis a compile-time error! Why would you want to modify something thatis about to vanish?

In modern C++, an rvalue is better thought of as “a value that can bemoved from”.

• Because it’s going to go away: prvalues, “pure rvalues”• Because the user deliberately used a cast or a function to say so:

xvaluesI “...we picked x for ... the unknown, the strange, the xpert only, or even

x-rated.” - Stroustrop

Roy Stogner Modern C++ May 10, 2017 39 / 59

Page 61: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Rvalue referencesIn C++11 we can now create a special “rvalue reference” type, using &&,which only binds to an rvalue:struct A { int i; };struct B { A a; };struct C : public A {};const A make_const_A();

A a;// A&& rr1 = a; // error: lvalue expression, rvalue referenceA&& rr2 = A();//A&& rr3 = B(); // error: type mismatchint&& rr4 = 42;//A&& rr5 = make_const_A(); // error: const object, non const

refconst A&& rr6 = make_const_A();const A&& rr7 = A(); // const ref, non-const object is fineA&& rr8 = B().a; // member of rvalue is rvalueA&& rr9 = C(); // rvalue references are still polymorphicA&& rr10 = std::move(a); // std::move returns an rvalue// A&& rr12 = rr11; // error: rvalue references are lvalues!

Roy Stogner Modern C++ May 10, 2017 40 / 59

Page 62: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Rvalue reference overloading

C++11 can declare functions which take and/or return rvalue references:

void f(int& x) { std::cout << "int&\n"; }void f(const int& x) { std::cout << "const int&\n"; }void f(int&& x) { std::cout << "int&&\n"; }

int i = 1;const int ci = 2;f(i); // calls f(int&)f(ci); // calls f(const int&)f(3); // calls f(int&&)

// would call f(const int&) if f(int&&) didn’t existf(std::move(i)); // calls f(int&&)

// rvalue reference variables are lvalue expressions!int&& x = 1;f(x); // calls f(int& x)f(std::move(x)); // calls f(int&& x)

Roy Stogner Modern C++ May 10, 2017 41 / 59

Page 63: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Method reference qualifiers

Roy Stogner Modern C++ May 10, 2017 42 / 59

Page 64: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Move semantics: assignment

A::operator=(A&& other) noexcept{_cheap_data = other._cheap_data; // "deep" copy_costly_data = std::move(other._costly_data); // sub-move_data_for_dtor = other._data_for_dtor;other._data_for_dtor = 0; // other *will* be destructed_raw_ptr = other._raw_ptr; // shallow copyother._raw_ptr = nullptr; // avoid double free

}

• Data at raw ptr need not be copied!

• No heap memory allocation! Just “steal” from the rvalue.

• std::move forces move semantics on heavyweight member data

Roy Stogner Modern C++ May 10, 2017 43 / 59

Page 65: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Move semantics: swapping

C++98 swap:

template <typename T>void swap(T& v1, T& v2) {

T temp = v1;v1 = v2;v2 = temp;

}

C++11 swap:

template <typename T>void swap(T& v1, T& v2) {

T temp = std::move(v1);v1 = std::move(v2);v2 = std::move(temp);

}

Roy Stogner Modern C++ May 10, 2017 44 / 59

Page 66: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Move semantics: uncopyable objectsDistinguishing between rvalue and lvalue function arguments is whatmakes unique ptr both safe and usable:

std::unique_ptr<int> factory_function();std::unique_ptr<int> up1 = new int(3);std::unique_ptr<int> up2;// up2 = up1; // error: unique things can’t be copiedup2 = factory_function(); // fine: the rvalue gets movedstd::auto_ptr<int> ap1 = new int(4), ap2 = new int(5);std::swap(ap1, ap2); // disasterstd::swap(up1, up2); // success

// disaster as soon as a resize, sort, etc. moves elementsstd::vector<std::auto_ptr<int> > vap;

// guaranteed well-defined:std::vector<std::unique_ptr<int> > vap;

• Useful for lightweight RAII objects too

Roy Stogner Modern C++ May 10, 2017 45 / 59

Page 67: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Move semantics: heavy temporary objectsVector/tensor/matrix operations use either user-managed workspace,inefficient temporary construction/destruction, move semantics, orexpression templates.

matrix3 = (c1*matrix1 + matrix2).inverse();

C++98:• Temporary constructed for c1*matrix1• Temporary constructed for c1*matrix1 + matrix2

• Temporary destroyed for c1*matrix1• Expensive reallocation, copy into matrix3• Temporary destroyed for c1*matrix1 + matrix2

C++11 move semantics, in one third the allocations:• Temporary constructed for c1*matrix1• c1*matrix1 + matrix2 can steal the first argument• Cheap destruction for now-empty argument• Cheap move into matrix3

Roy Stogner Modern C++ May 10, 2017 46 / 59

Page 68: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Universal referencesIf a variable or parameter is given type T&&, for some deduced type T, thatis sometimes called a “universal reference”.• Here “deduced type” roughly means “a function template parameter”,

“auto”, or (possibly?) “from a template or decltype metafunction”

• The && syntax here does not mean a subcategory of rvalue reference.• It means Stroustrop savors users’ confusion like a fine wine.

A universal reference becomes an rvalue reference if initialized by anrvalue, or an lvalue reference if initialized by an lvalue. It even preservesconst and volatile!template<typename T>void f(T&& param);void g(int&& param);

int i = 10;f(10); // param is of type int&&f(i); // param is of type int&// g(i); // error: cannot bind rvalue to lvalue

Roy Stogner Modern C++ May 10, 2017 47 / 59

Page 69: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Universal referencesIf a variable or parameter is given type T&&, for some deduced type T, thatis sometimes called a “universal reference”.• Here “deduced type” roughly means “a function template parameter”,

“auto”, or (possibly?) “from a template or decltype metafunction”• The && syntax here does not mean a subcategory of rvalue reference.

• It means Stroustrop savors users’ confusion like a fine wine.A universal reference becomes an rvalue reference if initialized by anrvalue, or an lvalue reference if initialized by an lvalue. It even preservesconst and volatile!template<typename T>void f(T&& param);void g(int&& param);

int i = 10;f(10); // param is of type int&&f(i); // param is of type int&// g(i); // error: cannot bind rvalue to lvalue

Roy Stogner Modern C++ May 10, 2017 47 / 59

Page 70: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Universal referencesIf a variable or parameter is given type T&&, for some deduced type T, thatis sometimes called a “universal reference”.• Here “deduced type” roughly means “a function template parameter”,

“auto”, or (possibly?) “from a template or decltype metafunction”• The && syntax here does not mean a subcategory of rvalue reference.• It means Stroustrop savors users’ confusion like a fine wine.

A universal reference becomes an rvalue reference if initialized by anrvalue, or an lvalue reference if initialized by an lvalue. It even preservesconst and volatile!template<typename T>void f(T&& param);void g(int&& param);

int i = 10;f(10); // param is of type int&&f(i); // param is of type int&// g(i); // error: cannot bind rvalue to lvalue

Roy Stogner Modern C++ May 10, 2017 47 / 59

Page 71: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Universal referencesIf a variable or parameter is given type T&&, for some deduced type T, thatis sometimes called a “universal reference”.• Here “deduced type” roughly means “a function template parameter”,

“auto”, or (possibly?) “from a template or decltype metafunction”• The && syntax here does not mean a subcategory of rvalue reference.• It means Stroustrop savors users’ confusion like a fine wine.

A universal reference becomes an rvalue reference if initialized by anrvalue, or an lvalue reference if initialized by an lvalue. It even preservesconst and volatile!template<typename T>void f(T&& param);void g(int&& param);

int i = 10;f(10); // param is of type int&&f(i); // param is of type int&// g(i); // error: cannot bind rvalue to lvalue

Roy Stogner Modern C++ May 10, 2017 47 / 59

Page 72: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Universal referencesTo be a universal reference, the type really must be deduced, directly:

template <typename T>struct A {f(T&& param);template <typename U>g(std::vector<U>&& param);template <typename V>h(const V&& param);template <typename W>i(W&& param);

}

A<int> a;int i = 10;// a.f(i); // error: cannot bind rvalue to lvalue// a.g(std::vector<int>{i}); // again// a.h(i); // and againa.i(i); // calls i with W&& as type int&

Roy Stogner Modern C++ May 10, 2017 48 / 59

Page 73: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding

What is the universal reference stuff good for? Forwarding an argument,including all type and value category information, from one function toanother. In C++1z they’re officially called “forwarding references”.

What is wrong with this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg arg) {do_stuff_with(arg);return shared_ptr<T>(new T(arg)); }

• Pass-by-value: may be slow

• Pass-by-value: may be impossible for uncopyable values

Roy Stogner Modern C++ May 10, 2017 49 / 59

Page 74: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding

What is the universal reference stuff good for? Forwarding an argument,including all type and value category information, from one function toanother. In C++1z they’re officially called “forwarding references”.

What is wrong with this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg arg) {do_stuff_with(arg);return shared_ptr<T>(new T(arg)); }

• Pass-by-value: may be slow

• Pass-by-value: may be impossible for uncopyable values

Roy Stogner Modern C++ May 10, 2017 49 / 59

Page 75: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding

What is the universal reference stuff good for? Forwarding an argument,including all type and value category information, from one function toanother. In C++1z they’re officially called “forwarding references”.

What is wrong with this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg arg) {do_stuff_with(arg);return shared_ptr<T>(new T(arg)); }

• Pass-by-value: may be slow

• Pass-by-value: may be impossible for uncopyable values

Roy Stogner Modern C++ May 10, 2017 49 / 59

Page 76: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding

What is the universal reference stuff good for? Forwarding an argument,including all type and value category information, from one function toanother. In C++1z they’re officially called “forwarding references”.

What is wrong with this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg arg) {do_stuff_with(arg);return shared_ptr<T>(new T(arg)); }

• Pass-by-value: may be slow

• Pass-by-value: may be impossible for uncopyable values

Roy Stogner Modern C++ May 10, 2017 49 / 59

Page 77: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via reference

What if we pass by reference instead?

template<typename T, typename Arg>shared_ptr<T> factory(Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Can’t call factory(10) or use any other constant argument!

What about const reference?

template<typename T, typename Arg>shared_ptr<T> factory(const Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Breaks for any functions which take a non-const reference!

Roy Stogner Modern C++ May 10, 2017 50 / 59

Page 78: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via reference

What if we pass by reference instead?

template<typename T, typename Arg>shared_ptr<T> factory(Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Can’t call factory(10) or use any other constant argument!

What about const reference?

template<typename T, typename Arg>shared_ptr<T> factory(const Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Breaks for any functions which take a non-const reference!

Roy Stogner Modern C++ May 10, 2017 50 / 59

Page 79: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via reference

What if we pass by reference instead?

template<typename T, typename Arg>shared_ptr<T> factory(Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Can’t call factory(10) or use any other constant argument!

What about const reference?

template<typename T, typename Arg>shared_ptr<T> factory(const Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Breaks for any functions which take a non-const reference!

Roy Stogner Modern C++ May 10, 2017 50 / 59

Page 80: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via reference

What if we pass by reference instead?

template<typename T, typename Arg>shared_ptr<T> factory(Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Can’t call factory(10) or use any other constant argument!

What about const reference?

template<typename T, typename Arg>shared_ptr<T> factory(const Arg& arg){ return shared_ptr<T>(new T(arg)); }

• Breaks for any functions which take a non-const reference!

Roy Stogner Modern C++ May 10, 2017 50 / 59

Page 81: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via forwarding referenceHow about this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(arg)); }

• Almost!• We match lvalue references, rvalue references, const, non-const...• But we aren’t forwarding all that: arg binds to an rvalue or lvalue, but

is itself always an lvalue

The solution:

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(std::forward<Arg>(arg))); }

• std::forward acts like move when presented with an rvaluereference, but does not change an lvalue reference

Roy Stogner Modern C++ May 10, 2017 51 / 59

Page 82: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via forwarding referenceHow about this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(arg)); }

• Almost!

• We match lvalue references, rvalue references, const, non-const...• But we aren’t forwarding all that: arg binds to an rvalue or lvalue, but

is itself always an lvalue

The solution:

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(std::forward<Arg>(arg))); }

• std::forward acts like move when presented with an rvaluereference, but does not change an lvalue reference

Roy Stogner Modern C++ May 10, 2017 51 / 59

Page 83: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via forwarding referenceHow about this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(arg)); }

• Almost!• We match lvalue references, rvalue references, const, non-const...

• But we aren’t forwarding all that: arg binds to an rvalue or lvalue, butis itself always an lvalue

The solution:

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(std::forward<Arg>(arg))); }

• std::forward acts like move when presented with an rvaluereference, but does not change an lvalue reference

Roy Stogner Modern C++ May 10, 2017 51 / 59

Page 84: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via forwarding referenceHow about this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(arg)); }

• Almost!• We match lvalue references, rvalue references, const, non-const...• But we aren’t forwarding all that: arg binds to an rvalue or lvalue, but

is itself always an lvalue

The solution:

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(std::forward<Arg>(arg))); }

• std::forward acts like move when presented with an rvaluereference, but does not change an lvalue reference

Roy Stogner Modern C++ May 10, 2017 51 / 59

Page 85: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding via forwarding referenceHow about this?

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(arg)); }

• Almost!• We match lvalue references, rvalue references, const, non-const...• But we aren’t forwarding all that: arg binds to an rvalue or lvalue, but

is itself always an lvalue

The solution:

template<typename T, typename Arg>shared_ptr<T> factory(Arg&& arg){ return shared_ptr<T>(new T(std::forward<Arg>(arg))); }

• std::forward acts like move when presented with an rvaluereference, but does not change an lvalue reference

Roy Stogner Modern C++ May 10, 2017 51 / 59

Page 86: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Forwarding references in the standard library

• move: turn lvalues into rvalues

• forward: move only lvalues which name rvalue references

• Insert and emplacement methods• bind: flexible closures in C++11

I (superceded by more flexible lambda in C++14)

• function::operator=: assign anything callable to a single shimclass type

• Threading methods

• make pair: create a pair of any types

• make tuple: create an N-tuple of any types

• forward as tuple: create a tuple of forwarded references

• tuple cat: concatenate tuples

Roy Stogner Modern C++ May 10, 2017 52 / 59

Page 87: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Wait, Tuples?

Defining std::pair is pretty simple:

template<typename T1, typename T2>struct pair {typedef T1 first_type;typedef T2 second_type;

T1 first;T2 second;

pair( const T1& x, const T2& y ){ first = x; second = y; }

// Other constructors, assignment, etc

• Defining a triple<T1,T2,T3> would be just as easy

• How do we define a tuple<T1,T2,T3,T4,etc>?

Roy Stogner Modern C++ May 10, 2017 53 / 59

Page 88: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Wait, Tuples?

Defining std::pair is pretty simple:

template<typename T1, typename T2>struct pair {typedef T1 first_type;typedef T2 second_type;

T1 first;T2 second;

pair( const T1& x, const T2& y ){ first = x; second = y; }

// Other constructors, assignment, etc

• Defining a triple<T1,T2,T3> would be just as easy

• How do we define a tuple<T1,T2,T3,T4,etc>?

Roy Stogner Modern C++ May 10, 2017 53 / 59

Page 89: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Wait, Tuples?

Defining std::pair is pretty simple:

template<typename T1, typename T2>struct pair {typedef T1 first_type;typedef T2 second_type;

T1 first;T2 second;

pair( const T1& x, const T2& y ){ first = x; second = y; }

// Other constructors, assignment, etc

• Defining a triple<T1,T2,T3> would be just as easy

• How do we define a tuple<T1,T2,T3,T4,etc>?

Roy Stogner Modern C++ May 10, 2017 53 / 59

Page 90: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Variadic arguments

C did this pretty well, if you didn’t care about type safety:

Roy Stogner Modern C++ May 10, 2017 54 / 59

Page 91: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Variadic templates

Roy Stogner Modern C++ May 10, 2017 55 / 59

Page 92: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Parameter packs

Roy Stogner Modern C++ May 10, 2017 56 / 59

Page 93: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Tuples

Roy Stogner Modern C++ May 10, 2017 57 / 59

Page 94: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Untying Tuples

Roy Stogner Modern C++ May 10, 2017 58 / 59

Page 95: PECOS C++ Sessions: Modern C++roystgnr/modern_cxx-talk.pdfSome language features are optional or belatedly supported: C++11-lite, C++14-lite, C++14, C++1z: without money/time/hexfloat

Lambda expressions

Roy Stogner Modern C++ May 10, 2017 59 / 59