This patch adds a __nth_element builtin that allows fetching the n-th type of a parameter pack with very little compile-time overhead. The patch was inspired by r252036 and r252115 by David Majnemer, which add a similar __make_integer_seq builtin for efficiently creating a std::integer_sequence.
We should probably consider changing the name from __nth_element to something else, perhaps something that contains the word "pack". This is especially true if we are to implement other intrinsics for manipulating parameter packs, like slicing (as proposed by Eric Fiselier). Unless someone with a clearer view of the project suggests something, I would probably go with __pack_element (and then we could add __pack_slice, etc...). I have no strong preference.
This patch also raises the question of whether we should have a more separated way of adding builtin templates. My job here was very easy because I just copied David's revision and tweaked a couple of things here and there, but I could imagine it not being obvious at all otherwise. Also, and most importantly, if we add other builtin templates, do we want these builtins to "clutter" the rest of the code instead of being somewhat isolated? I don't know the answer to these questions, but I'd just like to point them out.
It would be simpler and better (IMO) to have template <std::size_t Index, typename ...T> instead of template <typename IndexType, IndexType Index, typename ...T>, but I couldn't figure out how to create a non-type template parameter. Hence, I just adapted the code from David's revision for __make_integer_seq.
More generally, what is the proper way to retrieve a non-type template argument as a number that I can then use as a normal std::size_t (or similar) in the code? I really just want to retrieve the index, which is given as a non-type template parameter to __nth_element, and convert it to a numeric index n in order to fetch the n-th element of the parameter pack.
Please put the comma after BTK__make_integer_seq, not on this line.
Rename this createNthElementParameterList.
Use NonTypeTemplateParmDecl::Create. You can get size_t from ASTContext::getSizeType.
getExtValue is OK here, as we don't support size_t being larger than 64 bits.
If anything, I would probably start the name with __pack. This way, we could add other builtins that follow the same pattern, like __pack_slice, __pack_reverse and probably others.
Or if we don't want to start with __pack, then no problem, but we might want to settle on a prefix that will work for other builtins on packs as well.
Address Richard Smith's review comments:
- Remove IndexType parameter, and make Index a std::size_t
- Remove assertion about APSInt::GetExtValue()
- Other style changes
Still left to do:
- Settle on a name for __nth_element
- Should we produce a diagnostic when the index is out of bounds, or is this reserved for standard-mandated diagnostics (and we should use another mean to report the error)?
Address some remaining issues:
- Rename nth_element to type_pack_element, as suggested by Richard Smith
- Fix template parameter position issue in createTypePackElementParameterList
AFAICT, the only remaining issue is whether we should produce a diagnostic when the index is out of bounds, or whether this is reserved for standard diagnostics and we should use another mean to report the error. This is a trivial issue and I'll fix it or remove the TODO as soon as someone tells me the right way to go.
I'm really hoping that we can move forward with this patch.
Rebase the patch on top of the current master. The patch passes all of Clang's tests (make check-clang). I also removed the TODO comment about diagnostics, since that was answered by Richard Smith.