Другой ответ имеет правильное решение, но я думаю, что рассуждения не имеют ничего общего с параметрами, а вместо этого связаны с лямбда-захватом здесь:
constexpr int cnt = [/* &arr, */&is_even]()
Действительно, мы можем протестировать различные сценарии с помощью этогоcode:
#include <array>
#include <iostream>
template <size_t N>
constexpr int foo(const std::array<int, N>& arr) {
return [&arr] () { return arr.size(); }();
}
template <size_t N>
constexpr int bar(const std::array<int, N>& arr) {
int res{};
for (auto i : arr) {
res++;
}
return res;
}
template <size_t N>
constexpr int baz(const std::array<int, N>& arr) {
constexpr int test = [&arr] () constexpr {
return bar(arr);
}();
return test;
}
int main() {
constexpr std::array<int, 5> arr{11, 22, 33, 44, 55};
constexpr std::array<int, foo(arr)> test{};
constexpr std::array<int, bar(arr)> test2{};
constexpr std::array<int, baz(arr)> test3{};
}
Обратите внимание, что строка, в которой инициализируется test3
, не компилируется.Это, однако, компилируется просто отлично:
template <size_t N>
constexpr int baz(const std::array<int, N>& arr) {
return bar(arr);
}
Итак, в чем здесь проблема?Ну, лямбды на самом деле просто прославляемые функторы, и внутренне это будет выглядеть примерно так:
struct constexpr_functor {
const std::array<int, 5>& arr;
constexpr constexpr_functor(const std::array<int, 5>& test)
: arr(test) { }
constexpr int operator()() const {
return bar(arr);
}
};
// ...
constexpr constexpr_functor t{arr};
constexpr std::array<int, t()> test3{};
Обратите внимание, что теперь мы получаем сообщение об ошибке, показывающее реальную проблему:
test.cpp:36:33: note: reference to 'arr' is not a constant expression
test.cpp:33:34: note: declared here
constexpr std::array<int, 5> arr{11, 22, 33, 44, 55};
другой ответ цитирует книгу Скотта Мейера, но неверно истолковывает цитаты.Книга фактически показывает несколько примеров параметров, используемых в ситуациях constexpr, но в кавычках просто говорится, что если вы передадите параметр non-constexpr, функция может работать во время компиляции.