I have the following code:
static const char* ITEMS[] = { "a", "b" } // too many elements for a std::array in my situation
void my_func() {
printf("a: %d", index_of(ITEMS, "a")); // 0
printf("d: %d", index_of(ITEMS, "d")); // error at compile time; "d" does not exist in ITEMS.
}
How would I define a similar index_of method? I've seen various suggestions on other SO posts, but they don't work for the following reasons:
- Use
std::string/MakeITEMSaconstexpr- Unfortunately ImGui's
Comborequires aconst char**for the array type which is impossible withstd::string, and similarly, asITEMSwould be aconstexprit would be of typeconst char* const *, which does not work.
- Unfortunately ImGui's
- Use
std::arrayinstead ofT[]- The number of elements is too high for the compiler to handle, resulting in a compiler error.
CodePudding user response:
First, you must declare the array as constexpr. Otherwise its values are not usable at compile-time:
static constexpr const char* ITEMS[] = { "a", "b" };
As a consequence the type of the elements will be const char* const. If a library function expects them to be non-const then presumably that is because the library may attempt to modify them. That is of course impossible if they are supposed to be compile-time constants.
If you are absolutely sure that the library is simply lying about needing to modify the pointer value, then you can cast const away with const_cast. However, if the library then does attempt to modify the elements, then your program will have undefined behavior.
Then you also need C 20. Otherwise there is no way to force a compile-time error from failure of constant expression evaluation in a simple function call. Specifically you need the consteval feature.
With that:
template<typename R>
consteval auto index_of(const R& range, std::string_view needle) {
auto it = std::ranges::find(range, needle);
if(it == std::ranges::end(range))
throw std::logic_error("Element not found!");
return std::ranges::distance(std::ranges::begin(range), it);
}
This works with both built-in arrays and std::array.
Then you also need to replace %d with %zu, because the iterator difference type returned by this index_of is std::size_t for built-in arrays. %d is for the wrong type (int).
