the goal and the journey - turning back on one year of c++14 migration
TRANSCRIPT
Migration of C++ Libraries to C++14The Goal and the Journey
numscaleUnlocked software performance
Joel Falcou
NumScale SAS
Meeting C++ 2015
1 of 30
The Times, They’are-a-changing
Isn’t it 2015 already ?
� Code base migration to C++ 11/14 is a clear concern now� Time to support in compilers� Time to adopt the new standard
Worried ?
� Isn’t the new C++ even creepier ?� Is <feature X> really worth it ?� Will my coworkers get it ?
2 of 30
Sustainable C++
What is Sustainability for C++ ?
� Code intent must be obvious� Code must be clear for you and “future you”� Code must be clear for your coworkers
Are C++ 11 and 14 sustainable ?
� We claim that yes� Complex and simple tasks are easier� This talk is what we learnt
3 of 30
State of the union
What were we working on ?
� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment
Limitations of C++ 03
� Compile time� Complex customization point� Heavy dependency on Boost� Dependances on 3rd parties
5 of 30
State of the union
What were we working on ?
� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment
Limitations of C++ 03
� Compile time
� Complex customization point� Heavy dependency on Boost� Dependances on 3rd parties
5 of 30
State of the union
What were we working on ?
� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment
Limitations of C++ 03
� Compile time� Complex customization point
� Heavy dependency on Boost� Dependances on 3rd parties
5 of 30
State of the union
What were we working on ?
� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment
Limitations of C++ 03
� Compile time� Complex customization point� Heavy dependency on Boost
� Dependances on 3rd parties
5 of 30
State of the union
What were we working on ?
� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment
Limitations of C++ 03
� Compile time� Complex customization point� Heavy dependency on Boost� Dependances on 3rd parties
5 of 30
Ocean Eleven
Anticipated features
� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support
Anticipated Benet
� Shorter compile-time� Simpler interaction wit user� Less external dependency� Did I say shorter compile-time ?
7 of 30
Ocean Eleven
Anticipated features
� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support
Anticipated Benet
� Shorter compile-time
� Simpler interaction wit user� Less external dependency� Did I say shorter compile-time ?
7 of 30
Ocean Eleven
Anticipated features
� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support
Anticipated Benet
� Shorter compile-time� Simpler interaction wit user
� Less external dependency� Did I say shorter compile-time ?
7 of 30
Ocean Eleven
Anticipated features
� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support
Anticipated Benet
� Shorter compile-time� Simpler interaction wit user� Less external dependency
� Did I say shorter compile-time ?
7 of 30
Ocean Eleven
Anticipated features
� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support
Anticipated Benet
� Shorter compile-time� Simpler interaction wit user� Less external dependency� Did I say shorter compile-time ?
7 of 30
Initial migration
What we did rst
� Used auto/decltype here and there� Used variadic templates where it was obvious� Used std::future for threading� Used lambda as short-cut to algorithm customization
Well, well, well ...
� Underwhelming results : compile time still unpleasant� Smelly code to adapt lagging compilers� STL QoI varies wildly between compilers� Customization was still problematic
8 of 30
Initial migration
What we did rst
� Used auto/decltype here and there� Used variadic templates where it was obvious� Used std::future for threading� Used lambda as short-cut to algorithm customization
Well, well, well ...
� Underwhelming results : compile time still unpleasant� Smelly code to adapt lagging compilers� STL QoI varies wildly between compilers� Customization was still problematic
8 of 30
The Million Dollars Man
Lesson #1When migrating to C++ 14, consider rebuilding the
code base in a C++ 14 idiomatic way.
9 of 30
auto and decltype
Principles
� auto lets compiler nd the type of a variable� auto is usable as function return� decltype computes types of expressions
Effects
� Shorter, more generic code� Prevent type ‘intuition’ errors� Less symbol for the compiler to determine
11 of 30
auto and decltype
When to use auto ?
� Almost Always Auto (H. Sutter)� Except : non-template public API return type� Except : concrete type is needed for outside reasons� Caveat : auto deduction rules
When to use decltype ?
� Meta-programming tasks� SFINAE context in auto return type
12 of 30
Lesson Learnt
Lesson #2Follow the Almost Always Auto philosophy in a viral
way to ensure compile-time performance
13 of 30
Variadics Templates
Principles
� typename... Ts is a pack of types� Ts... is the pack expansion� Applicable to integral templates parameter� Applicable to lambdas parameters
Effects
� Less macros for variadics functions support� ... pack expansion generates code� ... works on arbitrary expression containing a pack
14 of 30
Variadics Templates examples
template<typename Pred, typename... Ts>struct all;
template<typename Pred, typename T>struct all : Pred::apply<T>::type{};
template<typename Pred, typename H, typename... Ts>struct all : and_ < typename all<Pred,H>::type
, typename all<Pred,Ts...>::type>
{};
15 of 30
Variadics Templates examples
template<bool... Bs> struct bools_ {};
template<typename Pred, typename... Ts>struct all : is_same< bools_<true, typename Pred<Ts>::type...>
, bools_<typename Pred<Ts>::type..., true>>
{};
15 of 30
Variadics Templates examples
template<typename F, typename... Ts>F for_each_args(F f, Ts&&...a){return initializer_list<int>{(ref(f)(forward<Ts>(a)),0)...}, f;
}
16 of 30
Variadics Templates
Turtles all the way down
� Don’t recurse variadics unless forced too� Each recursion generate symbols and need mangling� Instead, turn your code into something that can be comma separated
Effects
� Less symbols generated� Slimer executable� Faster compile-time
17 of 30
Lambda functions
Principles
� Anonymous function block� Can be variadic, generic� Generates magical callable object for you
Effects
� Code is more localized� Less work for the compiler� Enable higher-order programming
19 of 30
Anonymous functions
template<typename F, typename G>auto compose( F f, G g ){return [f,g](auto x) { return f(g(x)); }
}
auto sqr_sin = compose( [](float x) { return x*x; }, &::sinf)
auto x = sqr_fin(1.758f);
20 of 30
Anonymous functions
template<typename C, typename T, typename F>typename std::enable_if<C::value,T&&>::type select(T&& t, F&&){return std::forward<T>(t);
}
template<typename C, typename T, typename F>typename std::enable_if<!C::value,F&&>::type select(T&&, F&& f){return std::forward<F>(f);
}
20 of 30
Anonymous functions
// Somewhere in a container constructor
std::for_each ( begin, end, select<std::is_trivial<type>>
( [](auto ) {}, [&a](auto x) { alloc_t::construct(a,&x); })
);
20 of 30
Lesson Learnt
Lesson #4If your issues is solved by a higher order function, use
polymorphic/variadic lambdas functions
21 of 30
But wait, there’s more
Truths ...
� Lambda are just magic functor type� Lambda’s capture are stored as members� All done automagically by the compiler
... and Consequences
� Lambda can be used as throw-away struct� Those structs have function interface� Cheap way to get a tuple !
22 of 30
But wait, there’s more
Truths ...
� Lambda are just magic functor type� Lambda’s capture are stored as members� All done automagically by the compiler
... and Consequences
� Lambda can be used as throw-away struct� Those structs have function interface� Cheap way to get a tuple !
22 of 30
Rule #1 - Don’t speak about expression templates
Expression Templates in 4 bullets
� Way to implement DSL in C++� Operators evaluates a meta-AST� AST is transformed at compile-time� Allow arbitrary code generation for high level API
Known Issues
� Compile Time Hog� Complex code base (e.g Boost.Proto)� Interaction with C++ 11
23 of 30
The lambda tree that hides the type forest
Tree, Tuples, all the same
� Heterogeneous tuples are Trees� A AST is basically a types tree� Implements AST as tuples ...� ... tuple simplemented as lambda
Benets
� Lambda wash away symbol name� Better compile time because of shorter names� Correct behavior with move semantic
24 of 30
One sec, Hold My Beer !
template<typename C0, typename C1> auto as_expr(C0&& c0, C1&& c1){auto erase_type = [&]() {struct node {storage_type_t<C0&&> c0_;storage_type_t<C1&&> c1_;
explicit node(C0&& a, C1&& b): c0_{std::forward<C0>(a)}, c1_{std::forward<C1>(b)}
{}};
return node{std::forward<C0>(c0), std::forward<C1>(c1)};};
25 of 30
One sec, Hold My Beer !
using node = decltype(erase_type());return expr<node> { std::forward<C0>(c0)
, std::forward<C1>(c1)};
}
25 of 30
One sec, Hold My Beer !
template <typename T>auto f(T&& t){return as_expr(std::forward<T>(t), std::forward<T>(t));
}
some_type x;
std::cout << typeid(f(x)).name() << ”\n”;std::cout << typeid(f(f(x))).name() << ”\n”;std::cout << typeid(f(f(f(x)))).name() << ”\n”;std::cout << typeid(f(f(f(f(x))))).name() << ”\n”;
25 of 30
One sec, Hold My Beer !
expr<‘public: <lambda_009ab8f375e07b4c1155929143898761>::operator()(void)const ’::‘2’::node,void>
expr<‘public: <lambda_f2b41fa0275084c9467959ede97530cb>::operator()(void)const ’::‘2’::node,void>
expr<‘public: <lambda_37974d88904c635bc611f74424f19963>::operator()(void)const ’::‘2’::node,void>
expr<‘public: <lambda_ac503c8f3aa72c2953f3b0f0037dfa56>::operator()(void)const ’::‘2’::node,void>
25 of 30
Conclusion
What we learnt
� C++ 14 change the DNA of the language� Code must adapt to C++ 14 deeply� Don’t be afraid to be creative, it *is* rewarding
Hat tipping in the general direction of :
� Louis Dionne : GSoC student extraordinaire, Boost.Hana author� Agustín ”K-ballo” Bergé : Mind-blowing C++ guru� Edouard Alligand : brigand’s co-author� Jonathan Poelen : brigand’s day 1 adopter and contributor
28 of 30
Conclusion
What we learnt
� C++ 14 change the DNA of the language� Code must adapt to C++ 14 deeply� Don’t be afraid to be creative, it *is* rewarding
Hat tipping in the general direction of :
� Louis Dionne : GSoC student extraordinaire, Boost.Hana author� Agustín ”K-ballo” Bergé : Mind-blowing C++ guru� Edouard Alligand : brigand’s co-author� Jonathan Poelen : brigand’s day 1 adopter and contributor
28 of 30