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
/MakeITEMS
aconstexpr
- Unfortunately ImGui's
Combo
requires aconst char**
for the array type which is impossible withstd::string
, and similarly, asITEMS
would be aconstexpr
it would be of typeconst char* const *
, which does not work.
- Unfortunately ImGui's
- Use
std::array
instead 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
).