3. • Visual Studio 2010: Some features are supported
• Visual Studio 2012: Some more features are supported
Not supported yet
Visual Studio 2012
Visual Studio 2010
Automatic Concurrency Variadic
variables, library templates
decltype Memory Custom
Rvalue model literals
references Delegating
Lambda constructors
functions
• Comparison chart between many other compilers:
http://s.sashag.net/rpST0u
4. The problem with existing templates is that the
number of parameters is constant, consider:
tuple, printf, other type-safe va_list, …
template <typename T1> struct tuple {
T1 first;
};
template <typename T1, typename T2> struct tuple {
T1 first; T2 second;
};
template <typename T1, typename T2, typename T3> struct tuple {
T1 first; T2 second; T3 third;
};
//VC11 <tuple> does this with macros, going up to 10 parameters
5. New syntax for unbounded type parameter lists and
function parameter lists
“Dot-dot-dot is where the fun begins”
template <typename... Ts>
void foo(Ts&&... vs); //note: Ts is NOT a type, vs is NOT a variable
foo(42); foo(5, "Hello, World", vector<int>());
template <typename... Ts>
struct tuple; //requires some serious work!
tuple<int, float, string> tup(42, 42.0f, "42");
get<1>(tup) += 3.0f; cout << get<2>(tup) << endl;
6. New syntax for type list expansion
…and there’s also a new operator: sizeof...()
template <typename... Ts>
int passthrough_printf(const char* fmt, Ts&&... vs)
return printf(fmt, vs...);
}
template <typename... Ts>
class mixin : public Ts... {}; //will inherit from all Ts specified
//note: the following two statements ARE NOT THE SAME!
foo(goo(vs...)); ≡ foo(goo(v1, v2, v3));
foo(goo(vs)...); ≡ foo(goo(v1), goo(v2), goo(v3));
7. Typically, you have a base case that does something (or
nothing) and “recurse” to it from the variadic case
Not true recursion (different template)
template <typename... Ts>
void print(Ts&&... vs) {} //base case, will match empty list, do nothing
template <typename T, typename... Ts>
void print(T&& v, Ts&&... vs) {
cout << v << endl;
print(vs...); //”recursive” case; note that any decent compiler
} //will inline the whole thing into the caller
8. Alternatively, the base case can be a bounded number
of parameters to which we “recurse”
template <typename T1, typename T2>
bool assertContained(T1&& v1, T2&& v2) {
return v1 == v2;
}
template <typename T1, typename T2, typename... Ts>
bool assertContained(T1&& v1, T2&& v2, Ts&&... vs) {
return (v1 == v2 || assertContained(v1, vs...));
}
9. Using the compiler’s template mechanism to do work
at compile-time
Theorem: C++ templates are Turing-complete
//recursive case:
template <int N> struct fibo {
static const int value = fibo<N-1>::value + fibo<N-2>::value;
};
//base cases:
template <> struct fibo<0> { static const int value = 1; };
template <> struct fibo<1> { static const int value = 1; };
cout << fibo<14>::value; //compile-time!
11. We now develop a partial tuple<...>
(Practically) No limit on number of type parameters
Following A. Alexandrescu’s GoingNative 2012 talk
template <typename... Ts> struct tuple {};
template <typename T, typename... Ts>
struct tuple : private tuple<Ts...> {
T _head;
public:
tuple(T&& v, Ts&&... vs) :
_head(v), tuple<Ts...>(vs...) {}
//many more methods omitted
};
13. We need a way to declare the type of the k-th element
The get<N>() method will return it (later)
template <int, typename> struct tuple_elem;
template <typename T, typename... Ts>
struct tuple_elem<0, tuple<T,Ts...>> {
typedef T type; //this is the head, base case
};
template <int k, typename T, typename Ts...>
struct tuple_elem<k, tuple<T,Ts...>> {
typedef tuple_elem<k-1,Ts...>::type type; //recursion
};
14. template <int k, typename Ts...>
typename enable_if<k==0,
typename tuple_elem<k,Ts...>::type&>::type
get(tuple<Ts...>& tuple) {
return tuple._head; Why not a member
} //base case function on tuple?
template <int k, typename T, typename Ts...>
typename enable_if<k!=0,
typename tuple_elem<k,T,Ts...>::type&>::type
get(tuple<T,Ts...>& tuple) {
tuple<Ts...>& base = tuple;
get<k-1>(base); //recursion
}
15. tuple<int, float, string, employee> tup(...);
get<0>(tup) = 42;
get<3>(tup) = employee("John");
cout << get<3>(tup).name() << endl;
//Worth the effort. C# doesn’t have unlimited tuples!
//…and here’s another cool thing, Python-style:
tuple<int,bool> get_something() { ... }
How does this work?
int number; bool flag; tuple<T1&,T2&,…>
std::tie(number, flag) = get_something();
//now number, flag are the unpacked tuple!
16. • Primary concern: improve compiler errors
In file included from c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_tree.h:65:0,
from c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/map:60,
from ConceptsMotivation.cpp:2:
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = non_comparable]':
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_map.h:452:2: instantiated from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const
key_type&) [with _Key = non_comparable, _Tp = int, _Compare = std::less<non_comparable>, _Alloc = std::allocator<std::pair<const non_comparable, int> >, std::map<_Key, _Tp, _Compare,
_Alloc>::mapped_type = int, std::map<_Key, _Tp, _Compare, _Alloc>::key_type = non_comparable]'
ConceptsMotivation.cpp:8:20: instantiated from here
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_function.h:236:22: error: no match for 'operator<' in '__x < __y'
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_function.h:236:22: note: candidates are:
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_pair.h:207:5: note: template<class _T1, class _T2> bool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_iterator.h:291:5: note: template<class _Iterator> bool std::operator<(const std::reverse_iterator<_Iterator>&, const
std::reverse_iterator<_Iterator>&)
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_iterator.h:341:5: note: template<class _IteratorL, class _IteratorR> bool std::operator<(const std::reverse_iterator<_IteratorL>&, const
std::reverse_iterator<_IteratorR>&)
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_tree.h:856:5: note: template<class _Key, class _Val, class _KeyOfValue, class _Compare, class _Alloc> bool std::operator<(const std::_Rb_tree<_Key,
_Val, _KeyOfValue, _Compare, _Alloc>&, const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&)
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_map.h:894:5: note: template<class _Key, class _Tp, class _Compare, class _Alloc> bool std::operator<(const std::map<_Key, _Tp, _Compare, _Alloc>&,
const std::map<_Key, _Tp, _Compare, _Alloc>&)
c:mingwbin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_multimap.h:812:5: note: template<class _Key, class _Tp, class _Compare, class _Alloc> bool std::operator<(const std::multimap<_Key, _Tp, _Compare,
_Alloc>&, const std::multimap<_Key, _Tp, _Compare, _Alloc>&)
• Secondary: optimizations, better specialization, etc.
• Future feature: NOT PART OF C++ 11
17. The language compiler verifies that the generic type
performs only operations that are guaranteed to exist
on its type parameters
Limited set of constraints: base class, interface,
parameterless constructor
class SortedList<T> where T : IComparable<T> {
private T[] items;
public void Add(T item) {
//...can use item.CompareTo(otherItem) here
}
}
18. New keyword (concept)
Looks like a template class with no implementation
auto concept CopyConstructible<typename T> {
T(const T&);
};
auto concept Comparable<typename T> {
bool operator<(T, T);
};
auto concept Convertible<typename T, typename S> {
operator S(const T&);
};
19. To assert that a concept is available, use requires
Can specialize templates on concept requirements
template <typename T> requires LessThanComparable<T>
void sort(T* data, int length) { ... }
//instead of SFINAE:
template <typename T>
requires !LessThanComparable<T> && GreaterThanComparable<T>
void sort(T* data, int length) { ... }
20. Concepts can require other concepts
Concepts can derive from other concepts
concept InputIterator<typename Iter, typename Elem> {
requires CopyConstructible<Iter>;
Elem operator*(const Iter&);
Iter operator++(Iter&, int);
};
concept ForwardIterator<typename Iter, typename Elem>
: InputIterator<Iter, Value> {
//additional requirements
};
21. Specify how to bind a concept to an existing type
E.g., vector<T> was not designed to adhere to a stack
concept, but can be adapted after the fact
concept stack<typename C, typename T> {
void push(C&, const T&);
bool pop(C&, T&);
};
template <typename T> concept_map stack<vector<T>> {
void push(vector<T>& v, const T& t) { v.push_back(t); }
bool pop(vector<T>& v, T& t) { ... }
};
22. • enable_if “[…] is marred by a baroque syntax,
frequent and nontrivial corner cases, and interference
of mechanism with the exposed interface.”
– N3329 (draft proposal for static_if)
• Currently impossible to:
– Define a class member conditionally
– Easily share code between specializations
– Mix case-specific code within the same function
24. template <int N>
struct factorial { //remember fibo?
static_if (N <= 1) {
enum { value = 1 };
} else {
enum { value = factorial<N-1>::value * N };
}
};
//can replace many uses of concepts:
template <typename T> void sort(...)
if (has_operator_less_than<T>::value) { ... }
25. Proposal N3361 based on Intel Cilk
cilk_spawn, cilk_sync, cilk_for keywords
Akin to similar OpenMP pragmas
Additional suggestions for SIMD-friendly operators, such as
array slices and #pragma simd
cilk_for (auto c = customers.begin();
c != customers.end(); ++c) {
consider_vip_status(c);
adjust_discount(c);
}
26. Mirroring the success of C# 5’s await operator
Breaks down the method into a synchronous part and
one or more continuations
future<vector<image*>> download_profile_images(
vector<user> users) {
vector<image*> images;
webclient wc;
for (const auto& user : users)
images.push_back(new image(
await wc.download(user.profile_image_url()));
return images;
}
27. Transactional language constructs on top of software
transactional memory (N3341)
(By the way, Intel Haswell will have hardware TX semantics)
class Account {
void withdraw(int amount) {
__transaction { balance -= amount; }
}
};
void transfer(Account& a, Account& b, int amount) {
__transaction {
a.withdraw(amount); b.deposit(amount);
}
}
Not supported by VC11.To show the demo, use MinGW or any other gcc-clone (gcc 4.6.2 or higher is known to work).The quote (“dot dotdot is where the fun begins”) is from Andrei Alexandrescu’s talk at GoingNative 2012: http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadic
This is not up to date with the most recent proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf