Created
January 31, 2017 07:27
-
-
Save scraimer/6f0b584dd278d369e3b0cbcc4877e1f7 to your computer and use it in GitHub Desktop.
Find index of integer in template parameter pack in C++14
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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