Would be possible to iterate over a constexpr C-array/std::array/vector and execute constexpr operations on each element and everything to be done at compile time?
https://godbolt.org/z/5a4v3Eerh
#include <string_view>
using namespace std::string_view_literals;
constexpr std::string_view arr[] = {"ab"sv, "xyz"sv,};
int main(){
static_assert(arr[0] == "ab"); //OK
static_assert(arr[1] == "xyz");
#if 0 //would something like this be possible?
for(const auto i: arr){
static_assert(i == "xyz"); //???
}
#endif
return 0;
}
I used static_assert() but there could be any constexpr function ...
Any suggestion would be appreciated! any C++ standard (preferably the latest), any compiler (preferably Microsoft VisualStudio 2022)
This is a standard use case of std::index_sequence. C++20 templated lambdas make this easier.
[]<auto... Is>(std::index_sequence<Is...>){
([](){static_assert(arr[Is] == "xyz");}(), ...);
}(std::make_index_sequence<std::size(arr)>());
The inner lambda is needed because static_assert is a statement and cannot be used as an expression.
Note that this solution is subject to the translation limits on the maximal number of template parameters and may also be subject to the limit of the maximal level of template instantiations. Therefore, it may fail to compile if the array is too large.
Here is full example which prints useful diagnostics when assertions are falling:
namespace detail {
template <auto& Item, auto F>
constexpr bool checkItem()
{
static_assert(F(Item));
return F(Item);
}
template <auto& C, auto F, size_t... ints>
constexpr bool AllItemsAre(std::integer_sequence<size_t, ints...>)
{
return (checkItem<C[ints], F>() && ...);
}
} // namespace detail
template <auto& C, auto F>
constexpr bool AllItemsAre()
{
return detail::AllItemsAre<C, F>(std::make_index_sequence<std::size(C)> {});
}
Test code:
constexpr std::string_view arr[] = {
"ab"sv,
"xyz"sv,
#ifdef SHOW_FAILL
"zaQzs"sv,
#endif
"aad"sv,
};
constexpr bool isLower(std::string_view s)
{
return std::all_of(s.begin(), s.end(), [](auto ch) { return ch >= 'a' && ch <= 'z'; });
}
static_assert(AllItemsAre<arr, &isLower>());
Live demo
In case assertion fails:
<source>: In instantiation of 'constexpr bool detail::checkItem() [with auto& Item = arr[2]; auto F = isLower]':
<source>:17:34: required from 'constexpr bool detail::AllItemsAre(std::integer_sequence<long unsigned int, ints ...>) [with auto& C = arr; auto F = isLower; long unsigned int ...ints = {0, 1, 2, 3}]'
17 | return (checkItem<C[ints], F>() && ...);
| ~~~~~~~~~~~~~~~~~~~~~^~
<source>:24:37: required from here
24 | return detail::AllItemsAre<C, F>(std::make_index_sequence<std::size(C)> {});
| ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:43:41: in 'constexpr' expansion of 'AllItemsAre<arr, isLower>()'
<source>:43:32: error: static assertion failed
43 | static_assert(AllItemsAre<arr, &isLower>());
| ^~~~~~~~
<source>:43:32: note: 'isLower(arr[2])' evaluates to false
<source>:43:41: error: static assertion failed
43 | static_assert(AllItemsAre<arr, &isLower>());
<source>:10:19: error: static assertion failed due to requirement '&isLower(<null expr>)'
10 | static_assert(F(Item));
| ^~~~~~~
<source>:17:13: note: in instantiation of function template specialization 'detail::checkItem<arr[2], &isLower>' requested here
17 | return (checkItem<C[ints], F>() && ...);
| ^
<source>:24:20: note: in instantiation of function template specialization 'detail::AllItemsAre<arr, &isLower, 0UL, 1UL, 2UL, 3UL>' requested here
24 | return detail::AllItemsAre<C, F>(std::make_index_sequence<std::size(C)> {});
| ^
<source>:43:15: note: in instantiation of function template specialization 'AllItemsAre<arr, &isLower>' requested here
43 | static_assert(AllItemsAre<arr, &isLower>());
| ^
<source>:43:15: error: static assertion failed due to requirement 'AllItemsAre<arr, &isLower>()'
43 | static_assert(AllItemsAre<arr, &isLower>());
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>(10): error C2338: static_assert failed: 'F(Item)'
<source>(24): note: while evaluating constexpr function 'detail::AllItemsAre'
<source>(43): note: while evaluating constexpr function 'AllItemsAre'
<source>(10): note: the template instantiation context (the oldest one first) is
<source>(43): note: see reference to function template instantiation 'bool AllItemsAre<& arr,&bool isLower(std::string_view)>(void)' being compiled
<source>(24): note: see reference to function template instantiation 'bool detail::AllItemsAre<& arr,&bool isLower(std::string_view),0,1,2,3>(std::integer_sequence<size_t,0,1,2,3>)' being compiled
<source>(17): note: see reference to function template instantiation 'bool detail::checkItem<& arr[2],&bool isLower(std::string_view)>(void)' being compiled
<source>(43): error C2607: static assertion failed
Note for each compiler error logs contain arr[2] indicating on which item assertion has failed. So IMO this is a big win comparing to other similar answer(s).
I wonder if it is possible to improve it in such way that error message is more clear so it is easier to spot which item is a problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With