Skip to content

Instantly share code, notes, and snippets.

@scraimer
Created January 31, 2017 07:27
Show Gist options
  • Save scraimer/6f0b584dd278d369e3b0cbcc4877e1f7 to your computer and use it in GitHub Desktop.
Save scraimer/6f0b584dd278d369e3b0cbcc4877e1f7 to your computer and use it in GitHub Desktop.
Find index of integer in template parameter pack in C++14
// Forward declaration, so that helper knows about constexpr_find_in_int_parameter_pack
template <int V1, int... V_rest> struct constexpr_find_in_int_parameter_pack;
// Don't read this first, read the constexpr_find_in_int_parameter_pack first.
//
// Back? Good. This class *purely* to allow specializing the empty case using helper<>.
//
// The helper class allows us to separate the unpacking of the parameter pack (that is handled by
// constexpr_find_in_int_parameter_pack) from the stop condition (that is handled by the helper class). I
// couldn't figure out how to do both without in a single class.
template <int... V_rest> struct helper
{
template <int Needle> static constexpr int find_needle()
{
// The using here is just for readability
using on_rest = constexpr_find_in_int_parameter_pack<V_rest...>;
return on_rest::template find_needle<Needle>();
}
};
// This specialization of helper gives us the stop condition of the recursion. It always returns -1,
// since the needle is not present in the empty list.
template <> struct helper<>
{
template <int Needle> static constexpr int find_needle() { return -1; }
};
// This is the public interface of the class. It gives
//
// 1. Only need to input the list of integers and the needle, no need to input the length of the list
// 2. It checks the first integer in the list, and if it's the needle, we can stop.
// (Although keep in mind that the return doesn't stop C++ compiler from parsing the line that follows,
// so we had to create the helper to allow us to write legal C++ that expands the parameter pack,
// even when that parameter pack is empty.
// This constexpr_find_in_int_parameter_pack class always requires that the parameter pack have at
// least one more item in it, to assign to V1)
//
// Note: This finds the first instance of the needle.
template <int V1, int... V_rest> struct constexpr_find_in_int_parameter_pack
{
template <int Needle> static constexpr int find_needle()
{
// If the needle is here, return that it is in offset 0 from here.
if( V1 == Needle )
return 0;
// If the needle was in the V_rest, we need to update the offset of the V_rest from the
// beginning of the list, which also included V1. So we have to add 1 to it.
// But if the needle was not found, report that.
constexpr int const pos = helper<V_rest...>::template find_needle<Needle>();
return ( pos != -1 ) ? pos + 1 : -1;
}
};
int go()
{
// Search for 262 inside the list of {52, 52, 262, 131}, and report its offset
return constexpr_find_in_int_parameter_pack<52, 52, 262, 131>::find_needle<262>();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment