Use array as a tuple
After variadic template being supported by VC++ Nov 2012 CTP, the feature which will blow away most of our old code is supported by all of the major C++ compilers, and the next topic is how we use it well. A frequently raised question is that, how to expand a pack of arguments, like an std::tuple, to a function. Like, instead of writing
std::lock(l1, l2);
we want
std::tuple<std::mutex, std::mutex> t; vlock(t);
Now we already know the solution: the "indices trick"[1] -- to expand a variadic indices, not the arguments.
template <size_t... I> struct indices {}; template <size_t N, size_t... I> struct build_indices : build_indices<N - 1, N - 1, I...> {}; template <size_t... I> struct build_indices<0, I...> : indices<I...> {}; template <typename Tuple> using tuple_indices = build_indices<std::tuple_size<Tuple>::value>; template <typename Tuple> using tuple_indices = build_indices<std::tuple_size<Tuple>::value>; template <typename Tuple, size_t... I> void _vlock(Tuple&& t, indices<I...>) { std::lock(std::get<I>(std::forward<Tuple>(t))...); } template <typename Tuple> void vlock(Tuple& t) { _vlock(t, tuple_indices<Tuple>()); }
The best thing with the implementation I referred is that, it works with any type supporting the "tuple-like" protocol, e.g., std::pair, std::tuple, and std::array. The last one is very interesting since it provides both the tuple-like access and the STL container interfaces.
However, std::array has a tiny problem: its size template parameter has to be explicitly specified:
std::array<std::mutex, 2> t {};
So how about to use a native array instead? A trivial and evil approach is to specialize std::get, std::tuple_size and std::tuple_element before the definition of _vlock:
// unused specializations are omitted namespace std { template <size_t I, typename T, size_t N> auto get(T (&a)[N]) -> T& { static_assert(I < N, "out of range"); return a[I]; } template <typename T, size_t N> class tuple_size<T[N]> : public integral_constant<size_t, N> {}; } std::mutex t[] = { {}, {} }; // bad example... vlock(t);
However, to open the std namespace is not permitted by the standard. If you consider these specializations to be helpful, maybe you can submit a proposal to LWG.[2]
Links:
[1] The indices trick http://loungecpp.wikidot.com/tips-and-tricks%3Aindices
[2] How To Submit a Proposal http://isocpp.org/std/submit-a-proposal














