SlideShare a Scribd company logo
1 of 108
Download to read offline
Writing good std::future<C++>
Anton Bikineev, 2016
C++17 Standardization process.
What we wanted and expected…
• concepts
• ranges
• modules
• parallel algorithms
• .then on futures and other
concurrency features
• executors
• coroutines with await
• transactional memory
• contracts
• fold expressions
• uniform function call
syntax
• constexpr lambdas
• filesystem library
• networking library
• library features, e.g. any,
optional, etc…
• etc…
Writing good std::future<C++>
• concepts
• ranges
• modules
• parallel algorithms
• .then on futures and other
concurrency features
• executors
• coroutines with await
• transactional memory
• contracts
• fold expressions
• uniform function call
syntax
• constexpr lambdas
• filesystem library
• networking library
• library features, e.g. any,
optional, etc…
• etc…
C++17 Standardization process.
What we’ve got.
Writing good std::future<C++>
• concepts
• ranges
• modules
• parallel algorithms
• .then on futures and other
concurrency features
• executors
• coroutines with await
• transactional memory
• contracts
• fold expressions
• uniform function call
syntax
• constexpr lambdas
• filesystem library
• networking library
• library features, e.g. any,
optional, etc…
• etc…
C++17 Standardization process.
What we’ve got.
Kenny Kerr @kennykerr 7 march

C++11 attempted too much. C++14 xed that.

C++17 attempts too little. We need to x that.
Writing good std::future<C++>
Writing good std::future<C++>
C++’s view on polymorphism
Writing good std::future<C++>
C++’s view on polymorphism
class Factory
{
public:
virtual AbstractButton* createButton() = 0;
};
Writing good std::future<C++>
C++’s view on polymorphism
class Factory
{
public:
virtual std::unique_ptr<AbstractButton> createButton() = 0;
};
Writing good std::future<C++>
C++’s view on polymorphism
class Factory
{
public:
virtual std::unique_ptr<AbstractButton> createButton() = 0;
};
// use of polymorphic code
void createForm(Factory* factory)
{
auto button = factory->createButton();
}
Writing good std::future<C++>
C++’s view on polymorphism
// use of polymorphic code
void createForm(Factory* factory)
{
auto button = factory->createButton();
}
Writing good std::future<C++>
C++’s view on polymorphism
// use of polymorphic code
void createForm(Factory* factory)
{
auto button = factory->createButton();
}
Writing good std::future<C++>
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
<members>
Writing good std::future<C++>
ConcreteFactory
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
<members>
movq %rsp, %rbp
Writing good std::future<C++>
ConcreteFactory
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
<members>
factory
-24
movq %rdi, -24(%rbp)
Writing good std::future<C++>
ConcreteFactory
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
<members>
factory
-24
movq -24(%rbp), %rax
Writing good std::future<C++>
ConcreteFactory
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
factory
-24
<members>
vptr
<ptrs to funs>
&createButton
Writing good std::future<C++>
ConcreteFactory
vtable
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
factory
-24
<members>
vptr
<ptrs to funs>
&createButton
movq (%rax), %rax
Writing good std::future<C++>
ConcreteFactory
vtable
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
the function itself
factory
-24
<members>
vptr
<ptrs to funs>
&createButton
addq $8, %rax
Writing good std::future<C++>
ConcreteFactory
vtable
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
<members>
vptr
<ptrs to funs>
&createButton
factory
-24
the function itself
movq (%rax), %rax
Writing good std::future<C++>
ConcreteFactory
vtable
Dynamic polymorphism
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
<members>
vptr
<ptrs to funs>
&createButton
factory
-24
the function itselfcall %rax
Writing good std::future<C++>
ConcreteFactory
vtable
Dynamic polymorphism overhead
rsp
createForm frame
rbp
rdi
rax
x86_64 registers
…
<local vars, ra>
ConcreteFactory
<members>
vptr
vtable
<ptrs to funs>
&createButton
factory
-24
the function itself
Writing good std::future<C++>
C++ templates — solution?
template <class Factory>
void createForm(Factory& factory)
{
auto button = factory.createButton();
}
Writing good std::future<C++>
C++ templates — solution?
template <class Factory>
void createForm(Factory& factory)
{
auto button = factory.createButton();
}
template void createForm(ConcreteFactory&);
Writing good std::future<C++>
C++ static interface. CRTP
template <class Impl>
struct Factory
{
std::unique_ptr<AbstractButton> createButton()
{
return static_cast<Impl*>(this)->createButton();
}
};
Writing good std::future<C++>
C++ static interface. CRTP
template <class Impl>
struct Factory
{
std::unique_ptr<AbstractButton> createButton()
{
return static_cast<Impl*>(this)->createButton();
}
};
struct ConcreteFactory: Factory<ConcreteFactory>
{
std::unique_ptr<AbstractButton> createButton()
{
return std::make_unique<ConcreteButton>();
}
};
Writing good std::future<C++>
C++ static interface. Usage
template <class Impl>
void createForm(Factory<Impl>& fact)
{
auto button = fact.createButton();
}
template void createForm(Factory<ConcreteFactory>&);
Writing good std::future<C++>
CRTP problems
• looks like a hack;
• no possibility to get nested types from Impl;
• Impl is incomplete at point of instantiation.
Writing good std::future<C++>
Concepts — solution?
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> std::unique_ptr<AbstractButton>;
};
Writing good std::future<C++>
Concepts — solution?
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> std::unique_ptr<AbstractButton>;
};
template <class T>
requires factory<T>
void createForm(T& fact)
{
auto button = fact.createButton();
}
Writing good std::future<C++>
Concepts — solution?
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> std::unique_ptr<AbstractButton>;
};
template <factory T>
void createForm(T& fact)
{
auto button = fact.createButton();
}
Writing good std::future<C++>
Concepts — solution?
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> std::unique_ptr<AbstractButton>;
};
factory{T}
void createForm(T& fact)
{
auto button = fact.createButton();
}
Writing good std::future<C++>
Concepts — solution?
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> std::unique_ptr<AbstractButton>;
};
void createForm(factory& fact)
{
auto button = fact.createButton();
}
Writing good std::future<C++>
Dening concepts
template <class T>
concept bool variable_concept = constraint-expression;
template <class T>
concept bool function_concept()
{
return constraint-expression;
}
Writing good std::future<C++>
Dening concepts. Type traits
template <class T>
concept bool integral = std::is_integral<T>::value;
Writing good std::future<C++>
Dening concepts. Type traits
template <class T>
concept bool integral = std::is_integral<T>()();
Writing good std::future<C++>
Dening concepts. Type traits
// from library fundamentals TS
namespace std::experimental
{
template <class T>
constexpr bool is_integral_v = is_integral<T>::value;
}
namespace stde = std::experimental;
template <class T>
concept bool integral = stde::is_integral_v<V>;
Writing good std::future<C++>
Concepts. Iterator example
Writing good std::future<C++>
Concepts. Iterator example
template <class T>
concept bool iterator = ...;
Writing good std::future<C++>
Concepts. Iterator example
template <class T>
concept bool swappable = requires (T t)
{
{std::swap(t, t)} -> void;
}
or requires (T t)
{
// for ADL
{swap(t, t)} -> void;
};
Writing good std::future<C++>
Concepts. Iterator example
template <class T>
concept bool iterator = stde::is_copy_constructible_v<T>
and stde::is_copy_assignable_v<T>
and stde::is_destructible_v<T>
and swappable<T>
and requires (T r)
{
*r;
{++r} -> T&;
};
Writing good std::future<C++>
Concepts. Input iterator
template <class T>
concept bool equality_comparable = requires (T t)
{
{t == t} -> bool;
};
template <class T>
concept bool input_iterator = iterator<T>
and equality_comparable<T>;
Writing good std::future<C++>
Concepts. Forward iterator
Writing good std::future<C++>
Concepts. Forward iterator
template <class T>
concept bool forward_iterator = input_iterator<T>
and stde::is_default_constructible_v<T>
and requires (T r)
{
{r++} -> const T&;
};
Writing good std::future<C++>
Concepts. Bidirectional iterator
template <class T>
concept bool bidirectional_iterator = forward_iterator<T>
and requires (T r)
{
{--r} -> T&
{r--} -> const T&;
};
Writing good std::future<C++>
Concepts. Random access iterator
template <class T>
concept bool random_access_iterator = bidirectional_iterator<T>
and requires (T it,
typename std::iterator_traits<T>::difference_type n)
{
{it += n} -> T&;
{it + n} -> T;
{n + it} -> T;
{it -= n} -> T&;
{it - it} ->
typename std::iterator_traits<T>::difference_type;
{it[n]} ->
typename std::iterator_traits<T>::reference;
{it < it} -> bool;
{it <= it} -> bool;
{it > it} -> bool;
{it >= it} -> bool;
};
Concepts. Random access iterator
static_assert(forward_iterator<
std::forward_list<int>::iterator>);
Concepts. Iterators. Let’s test!
Writing good std::future<C++>
static_assert(forward_iterator<
std::forward_list<int>::iterator>);
static_assert(bidirectional_iterator<
std::list<int>::iterator>);
static_assert(bidirectional_iterator<
std::map<char, int>::iterator>);
Concepts. Iterators. Let’s test!
Writing good std::future<C++>
static_assert(forward_iterator<
std::forward_list<int>::iterator>);
static_assert(bidirectional_iterator<
std::list<int>::iterator>);
static_assert(bidirectional_iterator<
std::map<char, int>::iterator>);
static_assert(random_access_iterator<int*>);
static_assert(random_access_iterator<
std::vector<int>::iterator>);
static_assert(random_access_iterator<
std::deque<int>::iterator>);
Concepts. Iterators. Let’s test!
Writing good std::future<C++>
C++ generic programming and TMP
Writing good std::future<C++>
template <class _InputIterator>
vector(_InputIterator __first,
typename enable_if<
__is_input_iterator<_InputIterator>::value &&
!__is_forward_iterator<_InputIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<
_InputIterator>::reference>::value,
_InputIterator>::type __last);
template <class _ForwardIterator>
vector(_ForwardIterator __first,
typename enable_if<
__is_forward_iterator<_ForwardIterator>::value &&
is_constructible<
value_type,
typename iterator_traits<
_ForwardIterator>::reference>::value,
_ForwardIterator>::type __last);
Without concepts: libc++
Writing good std::future<C++>
vector(input_iterator __first, input_iterator __last);
vector(forward_iterator __first, forward_iterator __last);
With concepts: libc++
Writing good std::future<C++>
That’s it!
The greediness of T&&
Writing good std::future<C++>
// from Meyers’s EMC++ Item 26
std::multiset<std::string> names;
void logAndAdd(const std::string& name)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(name);
}
The greediness of T&&
Writing good std::future<C++>
// from Meyers’s EMC++ Item 26
std::multiset<std::string> names;
void logAndAdd(const std::string& name)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(name);
}
std::string petName("Darla");
logAndAdd(petName); // 1)
logAndAdd(std::string("Persephone")); // 2)
logAndAdd("Patty Dog”); // 3)
The greediness of T&&
Writing good std::future<C++>
// from Meyers’s EMC++ Item 26
std::multiset<std::string> names;
void logAndAdd(const std::string& name)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(name);
}
std::string petName("Darla");
logAndAdd(petName); // 1) okay, just copying
logAndAdd(std::string("Persephone")); // 2) extra copy
logAndAdd("Patty Dog”); // 3) no need to copy or move
The greediness of T&&
Writing good std::future<C++>
The greediness of T&&
// from Meyers’s EMC++ Item 26
template <typename T>
void logAndAdd(T&& name)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std::forward<T>(name));
}
std::string petName("Darla");
logAndAdd(petName); // 1) okay, just copying
logAndAdd(std::string("Persephone")); // 2) moving!
logAndAdd("Patty Dog”); // 3) neither moving nor copying,
// just creating inplaceWriting good std::future<C++>
// from Meyers’s EMC++ Item 26
std::string nameFromIdx(int idx);
void logAndAdd(int idx)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(nameFromIdx(idx));
}
short nameIdx;
logAndAdd(nameIdx); // error!
The greediness of T&&
Writing good std::future<C++>
Meyers, “Effective Modern C++”,
Item 26:
Avoid overloading on universal references.
The greediness of T&&
Writing good std::future<C++>
Meyers, “Effective Modern C++”,
Item 26:
Avoid overloading on universal references.
...
The greediness of T&&
Writing good std::future<C++>
Meyers, “Effective Modern C++”,
Item 26:
Avoid overloading on universal references.
...
but not on constrained universal references!
The greediness of T&&
Writing good std::future<C++>
void logAndAdd(int idx);
template <typename T>
void logAndAdd(T&& name)
{
...
names.emplace(std::forward<T>(name));
}
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
void logAndAdd(int idx);
template <typename T, typename =
std::enable_if_t<
stde::is_convertible_v<
T, std::string>>>
void logAndAdd(T&& name)
{
...
names.emplace(std::forward<T>(name));
}
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
void logAndAdd(int idx);
template <typename T, typename =
std::enable_if_t<
stde::is_convertible_v<
std::remove_reference_t<T>, std::string>>>
void logAndAdd(T&& name)
{
...
names.emplace(std::forward<T>(name));
}
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
void logAndAdd(int idx);
template <typename T, typename =
std::enable_if_t<
stde::is_convertible_v<
std::remove_reference_t<T>, std::string>>>
void logAndAdd(T&& name)
{
...
names.emplace(std::forward<T>(name));
}
short nameIdx;
logAndAdd(nameIdx); // calls logAndAdd(int) just fine!
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
template <class From, class To>
concept bool convertible =
stde::is_convertible_v<
std::remove_reference_t<From>, To>;
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
template <class From, class To>
concept bool convertible =
stde::is_convertible_v<
std::remove_reference_t<From>, To>;
void logAndAdd(convertible<std::string>&& name)
{
...
names.emplace(std::forward<decltype(name)>(name));
}
short nameIdx;
logAndAdd(nameIdx); // calls logAndAdd(int) just fine!
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
// from Meyers’s EMC++ Item 26
class Person {
public:
template <typename T>
explicit Person(T&& n) // perfect forwarding ctor
: name(std::forward<T>(n)) {}
explicit Person(int idx)
: name(nameFromIdx(idx)) {}
private:
std::string name;
};
Constrained T&&
as the best parameter type for efciency and safety
Writing good std::future<C++>
// from Meyers’s EMC++ Item 26
class Person {
public:
template <typename T>
explicit Person(T&& n) // perfect forwarding ctor
: name(std::forward<T>(n)) {}
explicit Person(int idx)
: name(nameFromIdx(idx)) {}
private:
std::string name;
};
Person p("Nancy");
auto cloneOfP(p); // WOW!
Constrained T&&
as the best parameter type for efciency and safety
// from Meyers’s EMC++ Item 26
class Person {
public:
explicit Person(convertible<std::string>&& n)
: name(std::forward<decltype(n)>(n)) {}
explicit Person(int idx)
: name(nameFromIdx(idx)) {}
private:
std::string name;
};
Person p("Nancy");
auto cloneOfP(p); // now works fine!
Constrained T&&
as the best parameter type for efciency and safety
std::future<C++> example:
flat_map
Writing good std::future<C++>
namespace boost::container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class Allocator =
std::allocator<std::pair<Key, Value>>>
class flat_map;
}
C++17 example: boost::flat_map
Writing good std::future<C++>
namespace mine::container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class UnderlyingContainer =
std::vector<std::pair<Key, Value>>>
class flat_map;
}
C++17 example: my flat_map
Writing good std::future<C++>
namespace mine::container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class UnderlyingContainer =
std::vector<std::pair<Key, Value>>>
requires default_constructible<Value>
class flat_map;
}
C++17 example: my flat_map
Writing good std::future<C++>
namespace mine::container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class UnderlyingContainer =
std::vector<std::pair<Key, Value>>>
requires default_constructible<Value>
and random_access_iterator<
typename UnderlyingContainer::iterator>
class flat_map;
}
C++17 example: my flat_map
Writing good std::future<C++>
namespace mine::container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class UnderlyingContainer =
std::vector<std::pair<Key, Value>>>
requires default_constructible<Value>
and random_access_iterator<
typename UnderlyingContainer::iterator>
and requires (Compare cmp, Key key)
{
{cmp(key, key)} -> bool;
}
class flat_map;
}
C++17 example: my flat_map
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
using key_type = Key;
using mapped_type = Value;
using underlying_type = UnderlyingContainer;
using typename underlying_type::value_type;
static_assert(stde::is_same_v<value_type,
std::pair<key_type, mapped_type>>);
using key_compare = Compare;
using value_compare = struct {
...
};
};
flat_map: typedefs
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
using value_compare = struct {
bool operator()(const value_type& left,
const value_type& right) const {
return key_compare()(left.first, right.first);
}
bool operator()(const key_type& left,
const value_type& right) const {
return key_compare()(left, right.first);
}
bool operator()(const value_type& left,
const key_type& right) const {
return key_compare()(left.first, right);
}};
};
flat_map: typedefs
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
using typename underlying_type::size_type;
using typename underlying_type::difference_type;
using typename underlying_type::allocator_type;
using typename underlying_type::reference;
using typename underlying_type::const_reference;
using typename underlying_type::pointer;
using typename underlying_type::const_pointer;
using typename underlying_type::iterator;
using typename underlying_type::const_iterator;
using typename underlying_type::reverse_iterator;
using typename underlying_type::const_reverse_iterator;
};
flat_map: typedefs
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
using underlying_type::begin; // laconic wrapping
using underlying_type::cbegin;
using underlying_type::end;
using underlying_type::cend;
using underlying_type::rbegin;
using underlying_type::crbegin;
using underlying_type::rend;
using underlying_type::crend;
};
flat_map: laconic wrapping
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
using underlying_type::swap;
using underlying_type::clear;
using underlying_type::empty;
using underlying_type::size;
using underlying_type::max_size;
using underlying_type::capacity;
using underlying_type::reserve;
using underlying_type::shrink_to_fit;
};
flat_map: laconic wrapping
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
flat_map() = default;
template <class Iterator>
flat_map(Iterator first, Iterator last):
underlying_type{first, last}
{
std::sort(begin(), end());
}
flat_map(std::initializer_list<value_type> list):
flat_map{list.begin(), list.end()}
{
}
};
flat_map: ctors
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
flat_map() = default;
flat_map(input_iterator first, input_iterator last):
underlying_type{first, last}
{
std::sort(begin(), end());
}
flat_map(std::initializer_list<value_type> list):
flat_map{list.begin(), list.end()}
{
}
};
flat_map: ctors
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
flat_map() = default;
flat_map(input_iterator first, input_iterator last):
underlying_type{first, last}
{
stde::sort(stde::par, begin(), end());
}
flat_map(std::initializer_list<value_type> list):
flat_map{list.begin(), list.end()}
{
}
};
flat_map: ctors
Writing good std::future<C++>
namespace detail
{
template <class Iterator, class Key, class Compare>
Iterator binary_search(Iterator begin,
Iterator end,
const Key& key,
const Compare& cmp)
{
auto it = std::lower_bound(begin, end, key, cmp);
if (it == end || cmp(key, *it))
return end;
return it;
}
}
flat_map: binary_search
Writing good std::future<C++>
namespace detail
{
auto binary_search(forward_iterator begin,
forward_iterator end,
const auto& key,
const auto& cmp)
{
auto it = std::lower_bound(begin, end, key, cmp);
if (it == end || cmp(key, *it))
return end;
return it;
}
}
flat_map: binary_search
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
iterator find(const key_type& key)
{
return detail::binary_search(
begin(), end(), key, value_compare{});
}
const_iterator find(const key_type& key) const
{
return detail::binary_search(
cbegin(), cend(), key, value_compare{});
}
};
flat_map: find
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
mapped_type& at(const key_type& key)
{
const auto it = find(key);
if (it == end()) throw std::range_error(“no key”);
return it->second;
}
const mapped_type& at(const key_type& key) const
{
// same as above
}
};
flat_map: at
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
std::pair<iterator, bool> emplace(
auto&& first, auto&&... args)
{
value_compare comp;
const auto it = std::lower_bound(
begin(), end(), first, comp);
if (it == end() || comp(first, *it))
return {underlying_type::emplace(it,
std::forward<decltype(first)>(first),
std::forward<decltype(args)>(args)...),
true};
return {it, false};
}
};
flat_map: emplace
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
std::pair<iterator, bool> insert(const value_type& value)
{
return emplace(value);
}
};
flat_map: insert
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
std::pair<iterator, bool> insert(const value_type& value)
{
return emplace(value);
}
std::pair<iterator, bool> insert(value_type&& value)
{
return emplace(std::move(value));
}
};
flat_map: insert
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
std::pair<iterator, bool> insert(
convertible<value_type>&& value)
{
return emplace(std::forward<decltype(value)>(value));
}
// no need to provide anything else!
};
flat_map: insert
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
void insert(input_iterator first,
input_iterator last)
{
const auto count = std::distance(first, last);
const auto room = capacity() - size();
if (room < count)
reserve(size() + count);
for (; first != last; ++first)
emplace(*first);
}
};
flat_map: insert
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
void insert(std::initializer_list<value_type> list)
{
insert(list.begin(), list.end());
}
};
flat_map: insert
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
mapped_type& operator[](convertible<key_type>&& key)
{
return emplace(
std::forward<decltype(key)>(key),
mapped_type{}
).first->second;
}
};
flat_map: index operator
Writing good std::future<C++>
template <...>
class flat_map final: private UnderlyingContainer
{
using underlying_type::erase;
size_type erase(const key_type& key)
{
const auto it = find(key);
if (it == end())
return 0u;
erase(it);
return 1u;
}
};
flat_map: erase
Writing good std::future<C++>
Modularizing flat_map. Interface
Writing good std::future<C++>
// flat_map.hpp
#include <...>
namespace container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class UnderlyingContainer =
std::vector<std::pair<Key, T>>>
class flat_map
{
...
};
}
Modularizing flat_map. Interface
Writing good std::future<C++>
// flat_map.ixx
#include <...>
module container.flat_map;
export namespace container
{
template <class Key, class Value,
class Compare = std::less<Key>,
class UnderlyingContainer =
std::vector<std::pair<Key, T>>>
class flat_map
{
...
};
}
Modularizing flat_map. Consuming
Writing good std::future<C++>
// main.cpp
import std.io;
import container.flat_map;
int main()
{
container::flat_map<std::string, int> map =
{{"second", 2}, {"first", 1}, {"third", 3}};
for (const auto& p: map)
std::cout << p.first << ": " << p.second << std::endl;
return 0;
}
Some more slides…
Writing good std::future<C++>
Static polymorphism with concepts.
Improving
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> std::unique_ptr<AbstractButton>;
};
void createForm(factory& fact)
{
auto button = fact.createButton();
}
Writing good std::future<C++>
Static polymorphism with concepts.
Improving
struct AbstractButton
{
virtual void onClick(std::function<void ()>) = 0;
virtual void onMove (std::function<void ()>) = 0;
};
Writing good std::future<C++>
Static polymorphism with concepts.
Improving
namespace detail // or std? or whatever
{
constexpr auto empty = [](auto...){};
}
template <class T>
concept bool button = requires (T t)
{
t.onClick(detail::empty);
t.onMove(detail::empty);
};
Writing good std::future<C++>
Static polymorphism with concepts.
Improving
template <class T>
concept bool button = ...;
template <class T>
concept bool factory = requires (T t)
{
{t.createButton()} -> button;
};
Writing good std::future<C++>
Static polymorphism with concepts.
Improving
class TButton
{
void onClick(...);
void onMove(...);
};
class QPushButton
{
void onClick(...);
void onMove(...);
};
Writing good std::future<C++>
Static polymorphism with concepts.
Improving
class TButton
{
void onClick(...);
void onMove(...);
};
class QPushButton
{
void onClick(...);
void onMove(...);
};
class VCLFactory
{
TButton createButton()
{
return TButton{};
}
};
class QtFactory
{
QPushButton createButton()
{
return QPushButton{};
}
};
Writing good std::future<C++>
Static polymorphism with concepts.
Using
void createForm(factory& fact)
{
auto button = fact.createButton();
button.onClick([]{ /* pum pum pum */ });
}
int main()
{
QtFactory factory;
createForm(factory);
QApplication::run();
}
Writing good std::future<C++>
Writing good std::future<C++>
Thank you for your attention!

More Related Content

What's hot

(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
Phil Calçado
 
Justjava 2007 Arquitetura Java EE Paulo Silveira, Phillip Calçado
Justjava 2007 Arquitetura Java EE Paulo Silveira, Phillip CalçadoJustjava 2007 Arquitetura Java EE Paulo Silveira, Phillip Calçado
Justjava 2007 Arquitetura Java EE Paulo Silveira, Phillip Calçado
Paulo Silveira
 
Javascript engine performance
Javascript engine performanceJavascript engine performance
Javascript engine performance
Duoyi Wu
 
Dr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slidesDr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slides
Dr-archana-dhawan-bajaj
 

What's hot (20)

Javascript Styles and some tips
Javascript Styles and some tipsJavascript Styles and some tips
Javascript Styles and some tips
 
Lisp Macros in 20 Minutes (Featuring Clojure)
Lisp Macros in 20 Minutes (Featuring Clojure)Lisp Macros in 20 Minutes (Featuring Clojure)
Lisp Macros in 20 Minutes (Featuring Clojure)
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
 
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
(ThoughtWorks Away Day 2009) one or two things you may not know about typesys...
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by Example
 
Justjava 2007 Arquitetura Java EE Paulo Silveira, Phillip Calçado
Justjava 2007 Arquitetura Java EE Paulo Silveira, Phillip CalçadoJustjava 2007 Arquitetura Java EE Paulo Silveira, Phillip Calçado
Justjava 2007 Arquitetura Java EE Paulo Silveira, Phillip Calçado
 
Introduction to Programming Bots
Introduction to Programming BotsIntroduction to Programming Bots
Introduction to Programming Bots
 
Let's refine your Scala Code
Let's refine your Scala CodeLet's refine your Scala Code
Let's refine your Scala Code
 
Javascript engine performance
Javascript engine performanceJavascript engine performance
Javascript engine performance
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Monte Carlo C++
Monte Carlo C++Monte Carlo C++
Monte Carlo C++
 
RESTful API using scalaz (3)
RESTful API using scalaz (3)RESTful API using scalaz (3)
RESTful API using scalaz (3)
 
Google Dart
Google DartGoogle Dart
Google Dart
 
Understanding Javascript Engines
Understanding Javascript Engines Understanding Javascript Engines
Understanding Javascript Engines
 
TypeScript Presentation - Jason Haffey
TypeScript Presentation - Jason HaffeyTypeScript Presentation - Jason Haffey
TypeScript Presentation - Jason Haffey
 
What's new in c#7
What's new in c#7What's new in c#7
What's new in c#7
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
 
GOCON Autumn (Story of our own Monitoring Agent in golang)
GOCON Autumn (Story of our own Monitoring Agent in golang)GOCON Autumn (Story of our own Monitoring Agent in golang)
GOCON Autumn (Story of our own Monitoring Agent in golang)
 
Dr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slidesDr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slides
 
The operation principles of PVS-Studio static code analyzer
The operation principles of PVS-Studio static code analyzerThe operation principles of PVS-Studio static code analyzer
The operation principles of PVS-Studio static code analyzer
 

Similar to Writing good std::future&lt;c++>

Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >
Sergey Platonov
 
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
HostedbyConfluent
 
C++ functions presentation by DHEERAJ KATARIA
C++ functions presentation by DHEERAJ KATARIAC++ functions presentation by DHEERAJ KATARIA
C++ functions presentation by DHEERAJ KATARIA
Dheeraj Kataria
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++Next
Sergey Platonov
 
Auto cad 2006_api_overview
Auto cad 2006_api_overviewAuto cad 2006_api_overview
Auto cad 2006_api_overview
scdhruv5
 
Connecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with EmbindConnecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with Embind
Chad Austin
 
Fp201 unit2 1
Fp201 unit2 1Fp201 unit2 1
Fp201 unit2 1
rohassanie
 

Similar to Writing good std::future&lt;c++> (20)

Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >Антон Бикинеев, Writing good std::future&lt; C++ >
Антон Бикинеев, Writing good std::future&lt; C++ >
 
Overview of C++20 and a deeper look into modules
Overview of C++20 and a deeper look into modulesOverview of C++20 and a deeper look into modules
Overview of C++20 and a deeper look into modules
 
Intro to c++
Intro to c++Intro to c++
Intro to c++
 
Pwning in c++ (basic)
Pwning in c++ (basic)Pwning in c++ (basic)
Pwning in c++ (basic)
 
Modern C++
Modern C++Modern C++
Modern C++
 
C++ functions
C++ functionsC++ functions
C++ functions
 
C++ Functions
C++ FunctionsC++ Functions
C++ Functions
 
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
Building Kafka Connectors with Kotlin: A Step-by-Step Guide to Creation and D...
 
JavaScript Robotics
JavaScript RoboticsJavaScript Robotics
JavaScript Robotics
 
Headache from using mathematical software
Headache from using mathematical softwareHeadache from using mathematical software
Headache from using mathematical software
 
C++ functions presentation by DHEERAJ KATARIA
C++ functions presentation by DHEERAJ KATARIAC++ functions presentation by DHEERAJ KATARIA
C++ functions presentation by DHEERAJ KATARIA
 
Learn c++ Programming Language
Learn c++ Programming LanguageLearn c++ Programming Language
Learn c++ Programming Language
 
C# What's next? (7.x and 8.0)
C# What's next? (7.x and 8.0)C# What's next? (7.x and 8.0)
C# What's next? (7.x and 8.0)
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++Next
 
Auto cad 2006_api_overview
Auto cad 2006_api_overviewAuto cad 2006_api_overview
Auto cad 2006_api_overview
 
Connecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with EmbindConnecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with Embind
 
Rcpp
RcppRcpp
Rcpp
 
Programming For Engineers Functions - Part #1.pptx
Programming For Engineers Functions - Part #1.pptxProgramming For Engineers Functions - Part #1.pptx
Programming For Engineers Functions - Part #1.pptx
 
Fp201 unit2 1
Fp201 unit2 1Fp201 unit2 1
Fp201 unit2 1
 
C++11 Idioms @ Silicon Valley Code Camp 2012
C++11 Idioms @ Silicon Valley Code Camp 2012 C++11 Idioms @ Silicon Valley Code Camp 2012
C++11 Idioms @ Silicon Valley Code Camp 2012
 

Recently uploaded

Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
Neometrix_Engineering_Pvt_Ltd
 
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
Health
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
mphochane1998
 
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
HenryBriggs2
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
jaanualu31
 

Recently uploaded (20)

Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
 
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
 
kiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal loadkiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal load
 
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARHAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
 
Minimum and Maximum Modes of microprocessor 8086
Minimum and Maximum Modes of microprocessor 8086Minimum and Maximum Modes of microprocessor 8086
Minimum and Maximum Modes of microprocessor 8086
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
 
Online food ordering system project report.pdf
Online food ordering system project report.pdfOnline food ordering system project report.pdf
Online food ordering system project report.pdf
 
Rums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdfRums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdf
 
Work-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptxWork-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptx
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
Bhubaneswar🌹Call Girls Bhubaneswar ❤Komal 9777949614 💟 Full Trusted CALL GIRL...
 
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
Air Compressor reciprocating single stage
Air Compressor reciprocating single stageAir Compressor reciprocating single stage
Air Compressor reciprocating single stage
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
 
Double Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueDouble Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torque
 
Engineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planesEngineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planes
 
Computer Lecture 01.pptxIntroduction to Computers
Computer Lecture 01.pptxIntroduction to ComputersComputer Lecture 01.pptxIntroduction to Computers
Computer Lecture 01.pptxIntroduction to Computers
 
Thermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - VThermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - V
 

Writing good std::future&lt;c++>

  • 2. C++17 Standardization process. What we wanted and expected… • concepts • ranges • modules • parallel algorithms • .then on futures and other concurrency features • executors • coroutines with await • transactional memory • contracts • fold expressions • uniform function call syntax • constexpr lambdas • lesystem library • networking library • library features, e.g. any, optional, etc… • etc… Writing good std::future<C++>
  • 3. • concepts • ranges • modules • parallel algorithms • .then on futures and other concurrency features • executors • coroutines with await • transactional memory • contracts • fold expressions • uniform function call syntax • constexpr lambdas • lesystem library • networking library • library features, e.g. any, optional, etc… • etc… C++17 Standardization process. What we’ve got. Writing good std::future<C++>
  • 4. • concepts • ranges • modules • parallel algorithms • .then on futures and other concurrency features • executors • coroutines with await • transactional memory • contracts • fold expressions • uniform function call syntax • constexpr lambdas • lesystem library • networking library • library features, e.g. any, optional, etc… • etc… C++17 Standardization process. What we’ve got. Kenny Kerr @kennykerr 7 march C++11 attempted too much. C++14 xed that. C++17 attempts too little. We need to x that. Writing good std::future<C++>
  • 6. C++’s view on polymorphism Writing good std::future<C++>
  • 7. C++’s view on polymorphism class Factory { public: virtual AbstractButton* createButton() = 0; }; Writing good std::future<C++>
  • 8. C++’s view on polymorphism class Factory { public: virtual std::unique_ptr<AbstractButton> createButton() = 0; }; Writing good std::future<C++>
  • 9. C++’s view on polymorphism class Factory { public: virtual std::unique_ptr<AbstractButton> createButton() = 0; }; // use of polymorphic code void createForm(Factory* factory) { auto button = factory->createButton(); } Writing good std::future<C++>
  • 10. C++’s view on polymorphism // use of polymorphic code void createForm(Factory* factory) { auto button = factory->createButton(); } Writing good std::future<C++>
  • 11. C++’s view on polymorphism // use of polymorphic code void createForm(Factory* factory) { auto button = factory->createButton(); } Writing good std::future<C++>
  • 12. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself <members> Writing good std::future<C++> ConcreteFactory
  • 13. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself <members> movq %rsp, %rbp Writing good std::future<C++> ConcreteFactory
  • 14. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself <members> factory -24 movq %rdi, -24(%rbp) Writing good std::future<C++> ConcreteFactory
  • 15. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself <members> factory -24 movq -24(%rbp), %rax Writing good std::future<C++> ConcreteFactory
  • 16. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself factory -24 <members> vptr <ptrs to funs> &createButton Writing good std::future<C++> ConcreteFactory vtable
  • 17. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself factory -24 <members> vptr <ptrs to funs> &createButton movq (%rax), %rax Writing good std::future<C++> ConcreteFactory vtable
  • 18. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> the function itself factory -24 <members> vptr <ptrs to funs> &createButton addq $8, %rax Writing good std::future<C++> ConcreteFactory vtable
  • 19. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> <members> vptr <ptrs to funs> &createButton factory -24 the function itself movq (%rax), %rax Writing good std::future<C++> ConcreteFactory vtable
  • 20. Dynamic polymorphism rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> <members> vptr <ptrs to funs> &createButton factory -24 the function itselfcall %rax Writing good std::future<C++> ConcreteFactory vtable
  • 21. Dynamic polymorphism overhead rsp createForm frame rbp rdi rax x86_64 registers … <local vars, ra> ConcreteFactory <members> vptr vtable <ptrs to funs> &createButton factory -24 the function itself Writing good std::future<C++>
  • 22. C++ templates — solution? template <class Factory> void createForm(Factory& factory) { auto button = factory.createButton(); } Writing good std::future<C++>
  • 23. C++ templates — solution? template <class Factory> void createForm(Factory& factory) { auto button = factory.createButton(); } template void createForm(ConcreteFactory&); Writing good std::future<C++>
  • 24. C++ static interface. CRTP template <class Impl> struct Factory { std::unique_ptr<AbstractButton> createButton() { return static_cast<Impl*>(this)->createButton(); } }; Writing good std::future<C++>
  • 25. C++ static interface. CRTP template <class Impl> struct Factory { std::unique_ptr<AbstractButton> createButton() { return static_cast<Impl*>(this)->createButton(); } }; struct ConcreteFactory: Factory<ConcreteFactory> { std::unique_ptr<AbstractButton> createButton() { return std::make_unique<ConcreteButton>(); } }; Writing good std::future<C++>
  • 26. C++ static interface. Usage template <class Impl> void createForm(Factory<Impl>& fact) { auto button = fact.createButton(); } template void createForm(Factory<ConcreteFactory>&); Writing good std::future<C++>
  • 27. CRTP problems • looks like a hack; • no possibility to get nested types from Impl; • Impl is incomplete at point of instantiation. Writing good std::future<C++>
  • 28. Concepts — solution? template <class T> concept bool factory = requires (T t) { {t.createButton()} -> std::unique_ptr<AbstractButton>; }; Writing good std::future<C++>
  • 29. Concepts — solution? template <class T> concept bool factory = requires (T t) { {t.createButton()} -> std::unique_ptr<AbstractButton>; }; template <class T> requires factory<T> void createForm(T& fact) { auto button = fact.createButton(); } Writing good std::future<C++>
  • 30. Concepts — solution? template <class T> concept bool factory = requires (T t) { {t.createButton()} -> std::unique_ptr<AbstractButton>; }; template <factory T> void createForm(T& fact) { auto button = fact.createButton(); } Writing good std::future<C++>
  • 31. Concepts — solution? template <class T> concept bool factory = requires (T t) { {t.createButton()} -> std::unique_ptr<AbstractButton>; }; factory{T} void createForm(T& fact) { auto button = fact.createButton(); } Writing good std::future<C++>
  • 32. Concepts — solution? template <class T> concept bool factory = requires (T t) { {t.createButton()} -> std::unique_ptr<AbstractButton>; }; void createForm(factory& fact) { auto button = fact.createButton(); } Writing good std::future<C++>
  • 33. Dening concepts template <class T> concept bool variable_concept = constraint-expression; template <class T> concept bool function_concept() { return constraint-expression; } Writing good std::future<C++>
  • 34. Dening concepts. Type traits template <class T> concept bool integral = std::is_integral<T>::value; Writing good std::future<C++>
  • 35. Dening concepts. Type traits template <class T> concept bool integral = std::is_integral<T>()(); Writing good std::future<C++>
  • 36. Dening concepts. Type traits // from library fundamentals TS namespace std::experimental { template <class T> constexpr bool is_integral_v = is_integral<T>::value; } namespace stde = std::experimental; template <class T> concept bool integral = stde::is_integral_v<V>; Writing good std::future<C++>
  • 37. Concepts. Iterator example Writing good std::future<C++>
  • 38. Concepts. Iterator example template <class T> concept bool iterator = ...; Writing good std::future<C++>
  • 39. Concepts. Iterator example template <class T> concept bool swappable = requires (T t) { {std::swap(t, t)} -> void; } or requires (T t) { // for ADL {swap(t, t)} -> void; }; Writing good std::future<C++>
  • 40. Concepts. Iterator example template <class T> concept bool iterator = stde::is_copy_constructible_v<T> and stde::is_copy_assignable_v<T> and stde::is_destructible_v<T> and swappable<T> and requires (T r) { *r; {++r} -> T&; }; Writing good std::future<C++>
  • 41. Concepts. Input iterator template <class T> concept bool equality_comparable = requires (T t) { {t == t} -> bool; }; template <class T> concept bool input_iterator = iterator<T> and equality_comparable<T>; Writing good std::future<C++>
  • 42. Concepts. Forward iterator Writing good std::future<C++>
  • 43. Concepts. Forward iterator template <class T> concept bool forward_iterator = input_iterator<T> and stde::is_default_constructible_v<T> and requires (T r) { {r++} -> const T&; }; Writing good std::future<C++>
  • 44. Concepts. Bidirectional iterator template <class T> concept bool bidirectional_iterator = forward_iterator<T> and requires (T r) { {--r} -> T& {r--} -> const T&; }; Writing good std::future<C++>
  • 46. template <class T> concept bool random_access_iterator = bidirectional_iterator<T> and requires (T it, typename std::iterator_traits<T>::difference_type n) { {it += n} -> T&; {it + n} -> T; {n + it} -> T; {it -= n} -> T&; {it - it} -> typename std::iterator_traits<T>::difference_type; {it[n]} -> typename std::iterator_traits<T>::reference; {it < it} -> bool; {it <= it} -> bool; {it > it} -> bool; {it >= it} -> bool; }; Concepts. Random access iterator
  • 50. C++ generic programming and TMP Writing good std::future<C++>
  • 51. template <class _InputIterator> vector(_InputIterator __first, typename enable_if< __is_input_iterator<_InputIterator>::value && !__is_forward_iterator<_InputIterator>::value && is_constructible< value_type, typename iterator_traits< _InputIterator>::reference>::value, _InputIterator>::type __last); template <class _ForwardIterator> vector(_ForwardIterator __first, typename enable_if< __is_forward_iterator<_ForwardIterator>::value && is_constructible< value_type, typename iterator_traits< _ForwardIterator>::reference>::value, _ForwardIterator>::type __last); Without concepts: libc++ Writing good std::future<C++>
  • 52. vector(input_iterator __first, input_iterator __last); vector(forward_iterator __first, forward_iterator __last); With concepts: libc++ Writing good std::future<C++> That’s it!
  • 53. The greediness of T&& Writing good std::future<C++>
  • 54. // from Meyers’s EMC++ Item 26 std::multiset<std::string> names; void logAndAdd(const std::string& name) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(name); } The greediness of T&& Writing good std::future<C++>
  • 55. // from Meyers’s EMC++ Item 26 std::multiset<std::string> names; void logAndAdd(const std::string& name) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(name); } std::string petName("Darla"); logAndAdd(petName); // 1) logAndAdd(std::string("Persephone")); // 2) logAndAdd("Patty Dog”); // 3) The greediness of T&& Writing good std::future<C++>
  • 56. // from Meyers’s EMC++ Item 26 std::multiset<std::string> names; void logAndAdd(const std::string& name) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(name); } std::string petName("Darla"); logAndAdd(petName); // 1) okay, just copying logAndAdd(std::string("Persephone")); // 2) extra copy logAndAdd("Patty Dog”); // 3) no need to copy or move The greediness of T&& Writing good std::future<C++>
  • 57. The greediness of T&& // from Meyers’s EMC++ Item 26 template <typename T> void logAndAdd(T&& name) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(std::forward<T>(name)); } std::string petName("Darla"); logAndAdd(petName); // 1) okay, just copying logAndAdd(std::string("Persephone")); // 2) moving! logAndAdd("Patty Dog”); // 3) neither moving nor copying, // just creating inplaceWriting good std::future<C++>
  • 58. // from Meyers’s EMC++ Item 26 std::string nameFromIdx(int idx); void logAndAdd(int idx) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(nameFromIdx(idx)); } short nameIdx; logAndAdd(nameIdx); // error! The greediness of T&& Writing good std::future<C++>
  • 59. Meyers, “Effective Modern C++”, Item 26: Avoid overloading on universal references. The greediness of T&& Writing good std::future<C++>
  • 60. Meyers, “Effective Modern C++”, Item 26: Avoid overloading on universal references. ... The greediness of T&& Writing good std::future<C++>
  • 61. Meyers, “Effective Modern C++”, Item 26: Avoid overloading on universal references. ... but not on constrained universal references! The greediness of T&& Writing good std::future<C++>
  • 62. void logAndAdd(int idx); template <typename T> void logAndAdd(T&& name) { ... names.emplace(std::forward<T>(name)); } Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 63. void logAndAdd(int idx); template <typename T, typename = std::enable_if_t< stde::is_convertible_v< T, std::string>>> void logAndAdd(T&& name) { ... names.emplace(std::forward<T>(name)); } Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 64. void logAndAdd(int idx); template <typename T, typename = std::enable_if_t< stde::is_convertible_v< std::remove_reference_t<T>, std::string>>> void logAndAdd(T&& name) { ... names.emplace(std::forward<T>(name)); } Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 65. void logAndAdd(int idx); template <typename T, typename = std::enable_if_t< stde::is_convertible_v< std::remove_reference_t<T>, std::string>>> void logAndAdd(T&& name) { ... names.emplace(std::forward<T>(name)); } short nameIdx; logAndAdd(nameIdx); // calls logAndAdd(int) just fine! Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 66. template <class From, class To> concept bool convertible = stde::is_convertible_v< std::remove_reference_t<From>, To>; Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 67. template <class From, class To> concept bool convertible = stde::is_convertible_v< std::remove_reference_t<From>, To>; void logAndAdd(convertible<std::string>&& name) { ... names.emplace(std::forward<decltype(name)>(name)); } short nameIdx; logAndAdd(nameIdx); // calls logAndAdd(int) just fine! Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 68. // from Meyers’s EMC++ Item 26 class Person { public: template <typename T> explicit Person(T&& n) // perfect forwarding ctor : name(std::forward<T>(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} private: std::string name; }; Constrained T&& as the best parameter type for efciency and safety Writing good std::future<C++>
  • 69. // from Meyers’s EMC++ Item 26 class Person { public: template <typename T> explicit Person(T&& n) // perfect forwarding ctor : name(std::forward<T>(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} private: std::string name; }; Person p("Nancy"); auto cloneOfP(p); // WOW! Constrained T&& as the best parameter type for efciency and safety
  • 70. // from Meyers’s EMC++ Item 26 class Person { public: explicit Person(convertible<std::string>&& n) : name(std::forward<decltype(n)>(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} private: std::string name; }; Person p("Nancy"); auto cloneOfP(p); // now works fine! Constrained T&& as the best parameter type for efciency and safety
  • 72. namespace boost::container { template <class Key, class Value, class Compare = std::less<Key>, class Allocator = std::allocator<std::pair<Key, Value>>> class flat_map; } C++17 example: boost::flat_map Writing good std::future<C++>
  • 73. namespace mine::container { template <class Key, class Value, class Compare = std::less<Key>, class UnderlyingContainer = std::vector<std::pair<Key, Value>>> class flat_map; } C++17 example: my flat_map Writing good std::future<C++>
  • 74. namespace mine::container { template <class Key, class Value, class Compare = std::less<Key>, class UnderlyingContainer = std::vector<std::pair<Key, Value>>> requires default_constructible<Value> class flat_map; } C++17 example: my flat_map Writing good std::future<C++>
  • 75. namespace mine::container { template <class Key, class Value, class Compare = std::less<Key>, class UnderlyingContainer = std::vector<std::pair<Key, Value>>> requires default_constructible<Value> and random_access_iterator< typename UnderlyingContainer::iterator> class flat_map; } C++17 example: my flat_map Writing good std::future<C++>
  • 76. namespace mine::container { template <class Key, class Value, class Compare = std::less<Key>, class UnderlyingContainer = std::vector<std::pair<Key, Value>>> requires default_constructible<Value> and random_access_iterator< typename UnderlyingContainer::iterator> and requires (Compare cmp, Key key) { {cmp(key, key)} -> bool; } class flat_map; } C++17 example: my flat_map Writing good std::future<C++>
  • 77. template <...> class flat_map final: private UnderlyingContainer { using key_type = Key; using mapped_type = Value; using underlying_type = UnderlyingContainer; using typename underlying_type::value_type; static_assert(stde::is_same_v<value_type, std::pair<key_type, mapped_type>>); using key_compare = Compare; using value_compare = struct { ... }; }; flat_map: typedefs Writing good std::future<C++>
  • 78. template <...> class flat_map final: private UnderlyingContainer { using value_compare = struct { bool operator()(const value_type& left, const value_type& right) const { return key_compare()(left.first, right.first); } bool operator()(const key_type& left, const value_type& right) const { return key_compare()(left, right.first); } bool operator()(const value_type& left, const key_type& right) const { return key_compare()(left.first, right); }}; }; flat_map: typedefs Writing good std::future<C++>
  • 79. template <...> class flat_map final: private UnderlyingContainer { using typename underlying_type::size_type; using typename underlying_type::difference_type; using typename underlying_type::allocator_type; using typename underlying_type::reference; using typename underlying_type::const_reference; using typename underlying_type::pointer; using typename underlying_type::const_pointer; using typename underlying_type::iterator; using typename underlying_type::const_iterator; using typename underlying_type::reverse_iterator; using typename underlying_type::const_reverse_iterator; }; flat_map: typedefs Writing good std::future<C++>
  • 80. template <...> class flat_map final: private UnderlyingContainer { using underlying_type::begin; // laconic wrapping using underlying_type::cbegin; using underlying_type::end; using underlying_type::cend; using underlying_type::rbegin; using underlying_type::crbegin; using underlying_type::rend; using underlying_type::crend; }; flat_map: laconic wrapping Writing good std::future<C++>
  • 81. template <...> class flat_map final: private UnderlyingContainer { using underlying_type::swap; using underlying_type::clear; using underlying_type::empty; using underlying_type::size; using underlying_type::max_size; using underlying_type::capacity; using underlying_type::reserve; using underlying_type::shrink_to_fit; }; flat_map: laconic wrapping Writing good std::future<C++>
  • 82. template <...> class flat_map final: private UnderlyingContainer { flat_map() = default; template <class Iterator> flat_map(Iterator first, Iterator last): underlying_type{first, last} { std::sort(begin(), end()); } flat_map(std::initializer_list<value_type> list): flat_map{list.begin(), list.end()} { } }; flat_map: ctors Writing good std::future<C++>
  • 83. template <...> class flat_map final: private UnderlyingContainer { flat_map() = default; flat_map(input_iterator first, input_iterator last): underlying_type{first, last} { std::sort(begin(), end()); } flat_map(std::initializer_list<value_type> list): flat_map{list.begin(), list.end()} { } }; flat_map: ctors Writing good std::future<C++>
  • 84. template <...> class flat_map final: private UnderlyingContainer { flat_map() = default; flat_map(input_iterator first, input_iterator last): underlying_type{first, last} { stde::sort(stde::par, begin(), end()); } flat_map(std::initializer_list<value_type> list): flat_map{list.begin(), list.end()} { } }; flat_map: ctors Writing good std::future<C++>
  • 85. namespace detail { template <class Iterator, class Key, class Compare> Iterator binary_search(Iterator begin, Iterator end, const Key& key, const Compare& cmp) { auto it = std::lower_bound(begin, end, key, cmp); if (it == end || cmp(key, *it)) return end; return it; } } flat_map: binary_search Writing good std::future<C++>
  • 86. namespace detail { auto binary_search(forward_iterator begin, forward_iterator end, const auto& key, const auto& cmp) { auto it = std::lower_bound(begin, end, key, cmp); if (it == end || cmp(key, *it)) return end; return it; } } flat_map: binary_search Writing good std::future<C++>
  • 87. template <...> class flat_map final: private UnderlyingContainer { iterator find(const key_type& key) { return detail::binary_search( begin(), end(), key, value_compare{}); } const_iterator find(const key_type& key) const { return detail::binary_search( cbegin(), cend(), key, value_compare{}); } }; flat_map: nd Writing good std::future<C++>
  • 88. template <...> class flat_map final: private UnderlyingContainer { mapped_type& at(const key_type& key) { const auto it = find(key); if (it == end()) throw std::range_error(“no key”); return it->second; } const mapped_type& at(const key_type& key) const { // same as above } }; flat_map: at Writing good std::future<C++>
  • 89. template <...> class flat_map final: private UnderlyingContainer { std::pair<iterator, bool> emplace( auto&& first, auto&&... args) { value_compare comp; const auto it = std::lower_bound( begin(), end(), first, comp); if (it == end() || comp(first, *it)) return {underlying_type::emplace(it, std::forward<decltype(first)>(first), std::forward<decltype(args)>(args)...), true}; return {it, false}; } }; flat_map: emplace Writing good std::future<C++>
  • 90. template <...> class flat_map final: private UnderlyingContainer { std::pair<iterator, bool> insert(const value_type& value) { return emplace(value); } }; flat_map: insert Writing good std::future<C++>
  • 91. template <...> class flat_map final: private UnderlyingContainer { std::pair<iterator, bool> insert(const value_type& value) { return emplace(value); } std::pair<iterator, bool> insert(value_type&& value) { return emplace(std::move(value)); } }; flat_map: insert Writing good std::future<C++>
  • 92. template <...> class flat_map final: private UnderlyingContainer { std::pair<iterator, bool> insert( convertible<value_type>&& value) { return emplace(std::forward<decltype(value)>(value)); } // no need to provide anything else! }; flat_map: insert Writing good std::future<C++>
  • 93. template <...> class flat_map final: private UnderlyingContainer { void insert(input_iterator first, input_iterator last) { const auto count = std::distance(first, last); const auto room = capacity() - size(); if (room < count) reserve(size() + count); for (; first != last; ++first) emplace(*first); } }; flat_map: insert Writing good std::future<C++>
  • 94. template <...> class flat_map final: private UnderlyingContainer { void insert(std::initializer_list<value_type> list) { insert(list.begin(), list.end()); } }; flat_map: insert Writing good std::future<C++>
  • 95. template <...> class flat_map final: private UnderlyingContainer { mapped_type& operator[](convertible<key_type>&& key) { return emplace( std::forward<decltype(key)>(key), mapped_type{} ).first->second; } }; flat_map: index operator Writing good std::future<C++>
  • 96. template <...> class flat_map final: private UnderlyingContainer { using underlying_type::erase; size_type erase(const key_type& key) { const auto it = find(key); if (it == end()) return 0u; erase(it); return 1u; } }; flat_map: erase Writing good std::future<C++>
  • 97. Modularizing flat_map. Interface Writing good std::future<C++> // flat_map.hpp #include <...> namespace container { template <class Key, class Value, class Compare = std::less<Key>, class UnderlyingContainer = std::vector<std::pair<Key, T>>> class flat_map { ... }; }
  • 98. Modularizing flat_map. Interface Writing good std::future<C++> // flat_map.ixx #include <...> module container.flat_map; export namespace container { template <class Key, class Value, class Compare = std::less<Key>, class UnderlyingContainer = std::vector<std::pair<Key, T>>> class flat_map { ... }; }
  • 99. Modularizing flat_map. Consuming Writing good std::future<C++> // main.cpp import std.io; import container.flat_map; int main() { container::flat_map<std::string, int> map = {{"second", 2}, {"first", 1}, {"third", 3}}; for (const auto& p: map) std::cout << p.first << ": " << p.second << std::endl; return 0; }
  • 100. Some more slides… Writing good std::future<C++>
  • 101. Static polymorphism with concepts. Improving template <class T> concept bool factory = requires (T t) { {t.createButton()} -> std::unique_ptr<AbstractButton>; }; void createForm(factory& fact) { auto button = fact.createButton(); } Writing good std::future<C++>
  • 102. Static polymorphism with concepts. Improving struct AbstractButton { virtual void onClick(std::function<void ()>) = 0; virtual void onMove (std::function<void ()>) = 0; }; Writing good std::future<C++>
  • 103. Static polymorphism with concepts. Improving namespace detail // or std? or whatever { constexpr auto empty = [](auto...){}; } template <class T> concept bool button = requires (T t) { t.onClick(detail::empty); t.onMove(detail::empty); }; Writing good std::future<C++>
  • 104. Static polymorphism with concepts. Improving template <class T> concept bool button = ...; template <class T> concept bool factory = requires (T t) { {t.createButton()} -> button; }; Writing good std::future<C++>
  • 105. Static polymorphism with concepts. Improving class TButton { void onClick(...); void onMove(...); }; class QPushButton { void onClick(...); void onMove(...); }; Writing good std::future<C++>
  • 106. Static polymorphism with concepts. Improving class TButton { void onClick(...); void onMove(...); }; class QPushButton { void onClick(...); void onMove(...); }; class VCLFactory { TButton createButton() { return TButton{}; } }; class QtFactory { QPushButton createButton() { return QPushButton{}; } }; Writing good std::future<C++>
  • 107. Static polymorphism with concepts. Using void createForm(factory& fact) { auto button = fact.createButton(); button.onClick([]{ /* pum pum pum */ }); } int main() { QtFactory factory; createForm(factory); QApplication::run(); } Writing good std::future<C++>
  • 108. Writing good std::future<C++> Thank you for your attention!