Вызов функции constexpr, принимающей массив, не компилируется
Рассмотрим этот код:
#include <array>
template < int... Ints >
constexpr std::array<int,sizeof...(Ints)> theIntArray = {Ints...};
template < size_t NN >
constexpr void test(const std::array<int,NN>& xx)
{
theIntArray<xx[0]>;
}
constexpr std::array<int,2> aa = {10,20};
int main()
{
theIntArray<aa[0]>; // passes
test(aa); // FAILS ?!
return 0;
}
в main()
Функция проходит первую строку, в то время как вторая строка завершается ошибкой со странным сообщением об ошибке:
error: ‘* & xx’ is not a constant expression
note: in template argument for type ‘int’
Я использую gcc-7.0.1, и вы можете найти живой пример здесь.
Это по стандарту или это баг? Что приводит к сбою второй строки при прохождении первой строки?
2 ответа
Все constexpr
функции должны быть действительны как с constexpr
и неconstexpr
аргументы. Или, короче говоря, аргументы constexpr
функция не constexpr
внутри тела, но если они constexpr
вне тела функции, в зависимости от них могут выполняться constexpr
по возвращении из функции.
theIntArray<xx[0]>;
это только правильный синтаксис, если xx[0]
является constexpr
, но в теле функции xx
не constexpr
,
template < size_t NN, std::array<int,NN> const& xx >
constexpr void test()
{
theIntArray<xx[0]>;
}
Разница в том, что параметр функции constexpr не существует. То есть вы не можете сделать
constexpr auto fun(int x) {
constexpr y = x;
return y;
}
и ни вы не можете использовать параметр функции xx[0]
в качестве нетипового шаблона-параметра внутри функции. Это отличается для aa[0]
потому что это оценивается вне функции.
Единственный способ сделать то, что вы хотите, это сделать параметр функции нетипичным параметром шаблона. Чтобы сделать это, посмотрите ответ @Yakk, где он использует const-ссылку на constexpr
массив как нетипичный параметр шаблона.